When a lambda expression is passed to a method it is possible to retrieve its return-type and the parameter-types (if specifically given by the caller) using type-parameters.
What I don't understand is that java seems to discard the type information given by the return-type of a lambda expression if the expression also uses the return-type as a parameter-type.
It is really hard to explain this question with words. Therefore I wrote the sample code below for further clarification.
//Case 1
@FunctionalInterface
interface Test<R> {
void returnValue(R takes);
}
static <R> R test(Test<R> test) {
//... Do something with test
}
public static void main(final String[] args) {
test((a) -> System.out.println("called"));
//This call will always return an Object
//This is clear. It is totally unnknow wich type a has at compile-time
}
//--------------------------------------------------------------------------
//Case 2
@FunctionalInterface
interface Test<R> {
R returnValue();
}
static <R> R test(Test<R> test) {
//... Do something with test
}
public static void main(final String[] args) {
test(() -> " ");
//This call will always return a String
//This is clear. R is specified to be a String by the return value.
}
//--------------------------------------------------------------------------
//Case 3
@FunctionalInterface
interface Test<R> {
R returnValue(R takes);
}
static <R> R test(Test<R> test) {
//... Do something with test
}
public static void main(final String[] args) {
test((a) -> " ");
//This call will always return an Object
//This it not clear. R is specified to be a String by the return value
//Why doesn't it return a String ?
}
Edit: Going deeper into the problem I noticed that the problem only really occurs when chaining calls. The code below demonstrates this. It was compiled in eclipse using java version 1.8.0_73.
package test;
public class TestLambdaGenerics {
@FunctionalInterface
interface Test<R> {
R returnValue(R takes);
}
static <R> Test<R> test(final Test<R> test) {
// ... Do something with test
return test;
}
public static void main(final String[] args) {
final Test<String> t = test((a) -> " ");
// Above works fine
final String t2 = test((a) -> " ").returnValue(" ");
// Above terminates with output:
// Exception in thread "main" java.lang.Error: Unresolved compilation problem:
// Type mismatch: cannot convert from Object to String
//
// at test.TestLambdaGenerics.main(TestLambdaGenerics.java:18)
}
}
Edit 2:
Question is resolved "chain-calling" with type-inference is just not supported by java at the moment.
See: this question or this article