In Java 1.8, the following lambda expression complies with both Runnable
and Callable
functional interfaces:
() -> {
throw new RuntimeException("FIXME");
}
Still, if I submit it to an ExecutorService
using a single-argument method, and ignore the return value (i. e. no type inference information is available), ExecutorService#submit(Callable)
is chosen at compile time, unless I explicitly cast my lambda to Runnable
.
How does the compiler choose between overloaded methods in the above case, provided that Runnable
and Callable
don't share any common hierarchy and most specific type rule doesn't apply here?
I believe this is because Callable
declares a return type, and Runnable
does not.
From the JLS section 15.12.2.5, the overload with the most specific type is chosen, if there is one unambiguously most specific. This is what it says about most specific functional interface types:
A functional interface type S is more specific than a functional interface type T for an expression e if T is not a subtype of S and one of the following is true (where U1 ... Uk and R1 are the parameter types and return type of the function type of the capture of S, and V1 ... Vk and R2 are the parameter types and return type of the function type of T):
If e is an explicitly typed lambda expression (§15.27.1), then one of the following is true:
- R2 is void...
T
is Runnable
, S
is Callable
, Callable
is more specific because its return type is not void, therefore Callable
is chosen
Method overload resolution is very complicated, so there may be a bit I've missed, but I think this is why it chooses Callable
Although @thecoop's answer is correct, there is another aspect of the lambda mechanism worth mentioning.
Lambdas with block bodies fall into two categories: void-compatible and value-compatible.
The lambda in the question is both, because it cannot complete normally (due to the unconditional exception throw) and all the return
statements in there are both valueless and returning a value, seeing as there's no return
statement at all.
Most lambdas however are either one or the other. And if the lambda is only void-compatible
, then the lambda will only be compatible with Runnable
.
What is slightly counter-intuitive (but logically correct) is that even though the lambda in the question never returns a value, it is classified as "always returning a value when there's a return
".
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