I recently came across below sample code where method reference operator is used to reference a method call. There are 2 questions for which i am looking for an answer 1. The execute method where its called expects Runnable class. This code compiles file and gives no error why (App class is not Runnable)? 2. if I replace executorService.execute(app::someMethod); with executorService.execute(app.someMethod()); it give an compile error why?
public class Temp {
private static final Logger LOGGER = LoggerFactory.getLogger(Temp.class);
/**
* @param args the command line arguments - not used
*/`enter code here`
public static void main(String... args) {
final App app = new App();
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 3; i++) {
executorService.execute(app::someMethod);
}
executorService.shutdown();
try {
executorService.awaitTermination(10, TimeUnit.SECONDS);
} catch (InterruptedException ie) {
LOGGER.error("ERROR: Waiting on executor service shutdown!");
}
}
}
class App {
public void someMethod() {
// Some logic
}
}
ExecutorService.execute
expects an argument of type Runnable
.
To answer your last question first... App.someMethod()
is a void
method (i.e. it doesn't return anything). As app.someMethod()
's return type is void
, and as the void
type cannot be assigned to a variable or method argument of type Runnable
, you are getting a compilation error.
Now, as to your first question... The Runnable
interface is a functional interface because it declares a single abstract method (SAM):
@FunctionalInterface
public interface Runnable {
void run();
}
The SAM here is void run()
, which doesn't receive any arguments and is a void
method.
Now, the method reference app::someMethod
is targeting the void someMethod()
method of the App
class, whose signature matches that one of the run
method of the Runnable
interface (by match I mean that both methods' return type is void
and that neither one of them receives any argument).
So, when you pass the app::someMethod
method reference as an argument to the executorService.execute
method, the compiler safely transforms it to a Runnable
instance.
EDIT: As user @MC Emperor highlights in the comments, the someMethod
method of the App
class may return something (i.e. it doesn't have to be necessarily a void
method). In this case, as stated by the spec (see JLS § 15.27.3, thanks for the link!), the return value would be simply discarded.
This is because in Java, values returned by methods can be discarded, and method references (and also lambda expressions) honor this behavior.
1) Yes, App class is not Runnable, but in your example it is not the App object that you are passing to execute method, but instead you do method reference there.
2) app::someMethod is a reference to an instance method of a particular object. app.someMethod() is just a call to someMethod() and it is expected that it returns an object implementing Runnable interface. It is not, that's why you get an error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With