Confusion in overloading println method, in Thread and ExecutorService

Viewed 135

I was reading the Effective Java edition 3 by Joshua Bloch in item 52, page 242 I encountered something strange that hope you Java heroes could help me demystify it. I quote exactly from the book:

The addition of lambdas and method references in Java 8 further increased the potential for confusion in overloading. For example, consider these two snippets:

new Thread(System.out::println).start();

ExecutorService exec = Executors.newCachedThreadPool();
exec.submit(System.out::println);

While the Thread constructor invocation and the submit method invocation look similar, the former compiles while the latter does not. The arguments are identical (System.out::println), and both the constructor and the method have an overloading that takes a Runnable. What’s going on here? The surprising answer is that the submit method has an overloading that takes a Callable, while the Thread constructor does not. You might think that this shouldn’t make any difference because all overloadings of println return void, so the method reference couldn’t possibly be a Callable. This makes perfect sense, but it’s not the way the overload resolution algorithm works. Perhaps equally surprising is that the submit method invocation would be legal if the println method weren’t also overloaded. It is the combination of the overloading of the referenced method (println) and the invoked method (submit) that prevents the overload resolution algorithm from behaving as you’d expect.

and author goes by giving the technical reason why the second method would not compile. again I didn't understand!

the problem is that System.out::println is an inexact method reference [JLS, 15.13.1] and that “certain argument expressions that contain implicitly typed lambda expressions or inexact method references are ignored by the applicability tests, because their meaning cannot be determined until a target type is selected [JLS, 15.12.2].”

when I tried the ExecutorService example in IDE(Intellij), it gave me this error:

reference to 'println' is ambiguous both 'println()' and 'println(boolean)' match

If I apply the following change the compile time error goes away. how this cast clarifies the ambiguity?

Executors.newCachedThreadPool().submit((Runnable) System.out::println);

my questions are first what is going on here, and second why IDE reported confusion between println() and println(boolean). Callable and Runnable don't want input parameters so by System.out::println we definitely mean println() in this context.

0 Answers
Related