Why does a lambda change overloads when it throws a runtime exception?

The problem is that there are two methods:

void fun(Runnable r) and void fun(Supplier<Void> s).

And an expression fun(() -> { throw new RuntimeException(); }).

Which method will be invoked?

According to JLS §15.12.2.1, the lambda body is both void-compatible and value-compatible:

If the function type of T has a void return, then the lambda body is either a statement expression (§14.8) or a void-compatible block (§15.27.2).

If the function type of T has a (non-void) return type, then the lambda body is either an expression or a value-compatible block (§15.27.2).

So both methods are applicable to the lambda expression.

But there are two methods so java compiler needs to find out which method is more specific

In JLS §15.12.2.5. It says:

A functional interface type S is more specific than a functional interface type T for an expression e if all of the following are true:

One of the following is:

Let RS be the return type of MTS, adapted to the type parameters of MTT, and let RT be the return type of MTT. One of the following must be true:

One of the following is:

RT is void.

So S (i.e. Supplier) is more specific than T (i.e. Runnable) because the return type of the method in Runnable is void.

So the compiler choose Supplier instead of Runnable.

Leave a Comment