Code compiles in Eclipse but not javac: curried lambdas with functional subinterface. Which is correct?
It looks like you run into JDK bug JDK-8156954 which has been fixed in Java 9 but not in Java 8.
It is a bug of Java 8 javac
because in your example all variable types of the transform
method can be inferred without violating the Java language specification as follows:
F
:String
(via first parameteroriginalList
of typeList<String>
)T
:IntToByteFunction
(via return typeList<IntToByteFunction>
)
These inferred variable types are compatible with the type of the second parameter, the chained lambda expression:
outer -> inner -> doStuff(inner, outer)
resolves (withdoStuff(Integer, String)
toString -> Integer -> doStuff(Integer, String)
resolves toString -> Integer -> Byte
is compatible withString -> IntToByteFunction
is compatible withMyFunction<? super String, ? extends IntToByteFunction>
Your example can be minimized further:
import java.util.function.Function;
class MinimalTypeFailureExample {
void foo() {
transform((Function<Integer, String>)null, o -> i -> {return "";});
}
<T, F> void transform(F f, MyFunction<T, ? extends F> m) {}
}
@FunctionalInterface
interface MyFunction<T, R> extends Function<T, R> {
@Override
R apply(T t);
}
MyFunction
overrides the same with the same (R apply(T t);
). If Function
instead of MyFunction
is used or if MyFunction
extends Function
but without @Override R apply(T t);
then the error disappears. Also with F
instead of ? extends F
the error disappears.
Even if your example differs from the example in the mentioned bug, it can be assumed that it is the same bug because it is the only "argument mismatch; bad return type in lambda expression bug that has been fixed in Java 9 but not in Java 8 and that occurs only with lambda functions in combination with Java Generics.