FULL PRODUCT VERSION :
java version "1.8.0_05"
Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Windows x64
OSX 10.9.4
A DESCRIPTION OF THE PROBLEM :
The compiler does not infer the correct type arguments for a method invocation that appears in a lambda body. The full example is on stackoverflow here: http://stackoverflow.com/questions/24986279/java-8-generics-exceptions-compile-time-error-when-using-a-lambda-expression/25101439#25101439
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile the following class with javac
import java.util.ArrayList;
import java.util.List;
public class JavaBugTest
{
interface AbleToThrowException<E extends Exception>
{
}
interface Parameter {
public <E extends Exception> Object execute(AbleToThrowException<E> algo) throws E;
}
interface ThrowsRuntimeException extends AbleToThrowException<RuntimeException>
{
}
static ThrowsRuntimeException foo;
public static Object manualLambda(Parameter p)
{
return p.execute(foo);
}
public static void main(String[] args)
{
List<Parameter> params = new ArrayList<>();
params.stream().map(p -> p.execute(foo)); // Gives a compile time error.
params.stream().map(JavaBugTest::manualLambda); // Works fine.
}
}
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The class should compile with 'p.execute(foo)` inferring 'RuntimeException' as its type argument.
ACTUAL -
We get a compilation error that is the result of the compiler failing to infer the correct type information.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
[~/test]$ javac JavaBugTest.java
JavaBugTest.java:30: error: unreported exception E; must be caught or declared to be thrown
params.stream().map((Parameter p) -> p.execute(foo)); // Gives a compile time error.
^
where E is a type-variable:
E extends Exception declared in method <E>execute(AbleToThrowException<E>)
1 error
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.ArrayList;
import java.util.List;
public class JavaBugTest
{
interface AbleToThrowException<E extends Exception>
{
}
interface Parameter {
public <E extends Exception> Object execute(AbleToThrowException<E> algo) throws E;
}
interface ThrowsRuntimeException extends AbleToThrowException<RuntimeException>
{
}
static ThrowsRuntimeException foo;
public static Object manualLambda(Parameter p)
{
return p.execute(foo);
}
public static void main(String[] args)
{
List<Parameter> params = new ArrayList<>();
params.stream().map(p -> p.execute(foo)); // Gives a compile time error.
params.stream().map(JavaBugTest::manualLambda); // Works fine.
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
You can explicitly provide the type argument
params.stream().map(p -> p.<RuntimeException>execute(foo)); // Gives a compile time error.