2

I have a class constitues 2 methods static and non static respectively, as per my limited knowledge submit method accepts runnable,callable instance directly or through lamba expression.

Today I came to know that we can even call or trigger static as well as non static method directly by using double colon which has been added in java 8.

I was just wondering how this works, there is no run method in my class and it doesn't implements runnable and even I'm not using lamba?

Is it a good practice to use :: or one should pass the runnable or callable instance.

Is there any other way to call a method inside submit() rather passing an instance?

Class A {

public static void printSomething(){
System.out.println("Staitc Method");
}

public void print()
{
System.out.println("Non-Staitc Method");
}

}

psvm()
{
A a = new A():
ExecutorService es = Executors.newFixedThreadPool(2);
es.submit(A::printSomething);  //Expected is runnable or callable task
es.submit(a::print);
}

Shelly
  • 183
  • 1
  • 1
  • 11
  • You can `es.submit(() -> { // code/invoke a void method here });`. The `run` method invokes your `print` methods. – Naman Apr 01 '20 at 12:17
  • @Naman this is lambda expression which works, indirectly it is run method, but how :: works? – Shelly Apr 01 '20 at 12:29
  • The linked question answers that nicely with varied examples in different answers. – Naman Apr 01 '20 at 13:26

3 Answers3

3

A::printSomething is called a method reference. When you use a method reference in a place that expects an interface like Runnable or Callable, Java automatically creates an implementation of that interface that calls the method.

That is,

es.submit(A::printSomething);

behaves the same as

es.submit(new Runnable() {
    public void run() {
        A.printSomething();
    }
});

but is easier to read and does not create a new class everywhere you use it, or a new object instance every time it's called.

You can read more about method references in

Another way of achieving the same is using lambda expressions such as:

es.submit(() -> A.printSomething());
Joni
  • 108,737
  • 14
  • 143
  • 193
2

Since Runnable is a functional interface, you can use lambda expressions or method references that fit it even if the method name doesn't match. Therefore any no-arg void method can be used as a Runnable.

Runnable r1 = () -> a.printSomething();
Runnable r2 = A::printSomething();  // Method reference, short-hand
Runnable r3 = () -> A.printSomething(); // Same as r2, but as explicit lambda expression
Kayaman
  • 72,141
  • 5
  • 83
  • 121
1

The reason why the method reference works even though the class does not implement a void run() method is because what matters for Functional Interface assignment is the method signature and not the method names.

The method signature of A's printSomething matches Runnable's run and for that reason it works. Notice this only works with Functional Interfaces (i.e. those with only one method, said method method not having a default implementation).

Is it good practice? It's a matter of style but it is definitely not bad practice to use method references, and they're also more concise than left -> right lambdas.

I suggest you try this out yourself so you're clear on the rules.

public class FunctionalInterfaceDemo {

  public static class SimpleClass {
    public static void doItStatic() {
    }

    public void doItNonStatic() {
    }
  }

  interface MyOwnFunctionalInterface {
    void methodA();
  }

  interface NotAFunctionalInterface {
    void methodA();

    void methodB();
  }

  interface AlsoNotAFunctionalInterface {
    default void methodA() {
    }
  }


  public static void main(String[] args) {
    MyOwnFunctionalInterface compiles = SimpleClass::doItStatic;
    MyOwnFunctionalInterface alsoCompiles = new SimpleClass()::doItNonStatic;
    NotAFunctionalInterface doesNotCompile = SimpleClass::doItStatic;
    AlsoNotAFunctionalInterface alsoDoesNotCompile = SimpleClass::doItStatic;
  }

}

edu
  • 428
  • 2
  • 10