Search code examples
javalambda

How does the compiler know which class the lambda is implementing?


I see Thread() takes both Runnable and String for single argument constructors. How does the compiler know that a lambda is implementing a Runnable class and not a String class?

    (new Thread( () -> {
        System.out.println("Deleting stats...");
    })).start();

Maybe it goes by the number of methods in the class/interface? But what if a class had multiple constructors that took single argument class that only had one method, for example:

Thread( Runnable r );
Thread( Comparable c );
Thread( ActionListener al );

What happens then when you try to implement a lambda then? How would the compiler know which class the lambda is implementing?


Solution

  • The Java compiler must choose a functional interface type for the type of a lambda expression. This is governed by the JLS, Section 15.27.3, which states:

    A lambda expression is compatible in an assignment context, invocation context, or casting context with a target type T if T is a functional interface type (§9.8) and the expression is congruent with the function type of the ground target type derived from T.

    The type String is not a functional interface type, but Runnable is. The lambda takes no arguments and returns no data, so it is congruent with Runnable.

    More generally, the types of parameters in a lambda expression must match the types of parameters of the single abstract method of a functional interface type, and the return types must match also.

    In your example, each of the 3 functional interface types is distinct, so at most one will match. If there are multiple functional interface types that could possible match, that would be ambiguous, only resolvable by casting the lambda expression to the intended functional interface type.