Why is lambda return type not checked at compile time?

Its the type inference that is playing its role here. Consider the generic R in the method signature:

<R> Builder<T> with(Function<T, R> getter, R returnValue)

In the case as listed:

Builder.of(MyInterface.class).with(MyInterface::getLength, "I am NOT an Integer");

the type of R is successfully inferred as

Serializable, Comparable<? extends Serializable & Comparable<?>>

and a String does imply by this type, hence the compilation succeeds.


To explicitly specify the type of R and find out the incompatibility, one can simply change the line of code as :

Builder.of(MyInterface.class).<Integer>with(MyInterface::getLength, "not valid");

In the first example, MyInterface::getLength and "I am NOT an Integer" helped to resolve the generic parameters T and R to MyInterface and Serializable & Comparable<? extends Serializable & Comparable<?>>respectively.

// it compiles since String is a Serializable
Function<MyInterface, Serializable> function = MyInterface::getLength;
Builder.of(MyInterface.class).with(function, "I am NOT an Integer");

MyInterface::getLength is not always a Function<MyInterface, Integer> unless you explicitly say so, which would lead to a compile-time error as the second example showed.

// it doesn't compile since String isn't an Integer
Function<MyInterface, Integer> function = MyInterface::getLength;
Builder.of(MyInterface.class).with(function, "I am NOT an Integer");