Consider the following code sample:
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List list = new ArrayList();
String response = getProducer(list).get();
}
static Producer getProducer(List list) {
return new Producer();
}
}
class Producer {
T get() {
return null;
}
}
When compiled in Java 7 it just produces an expected warning for getProducer(list):
Warning:(7, 39) java: unchecked conversion
required: java.util.List
found: java.util.List
However, when compiled in Java 8 it produces the following error for the response = getProducer(list).get() assignment:
Error:(7, 48) java: incompatible types: java.lang.Object cannot be converted to java.lang.String
So apparently the type returned from getProducer(list) is not Producer, but erased Producer (which is also confirmed by means of the 'extract variable' feature in the IDE). This is very puzzling because getProducer method always returns Producer.
Oddly enough it could be fixed by avoiding unchecked conversion while calling getProducer method, either by:
Change parameter type of getProducer from List to List
Change type of list variable from List to List
Updates
Java used is Oracle JDK 1.8.0_40
I have also tried using source and target options from 1.5 through 1.7 with the Java 8 compiler and the result was the same.
Questions
How could the generic type of the passed argument affect a generic type of the method return value while the generic type of the return value is fixed in the method signature?
Why is there such a backward-incompatible change in behavior between Java 7 and Java 8?
解决方案
This looks like a known compatibility issue reported here and here.
From the second link:
The following code which compiled, with warnings, in JDK 7 will not
compile in JDK 8:
import java.util.List;
class SampleClass {
static class Baz {
public static List> sampleMethod(Baz param) {
return null;
}
}
private static void bar(Baz arg) {
Baz element = Baz.sampleMethod(arg).get(0);
}
}
Compiling this code in JDK 8 produces the following error:
SampleClass.java:12: error:incompatible types: Object cannot be
converted to Baz
Baz element = Baz.sampleMethod(arg).get(0);
Note: SampleClass.java uses unchecked or unsafe operations. Note:
Recompile with -Xlint:unchecked for details. 1 error
Deriving from this, the OP's code can be fixed by replacing this line (the type declartion on the right hand side threw me off - I read it as a typed array list which it is not):
List list = new ArrayList();
with
List list = new ArrayList();
which will not result in type being being erased from return type of method getProducer(List list)
Quote from second link again:
In this example, a raw type is being passed to the
sampleMethod(Baz) method which is applicable by subtyping (see
the JLS, Java SE 7 Edition, section 15.12.2.2). An unchecked
conversion is necessary for the method to be applicable, so its return
type is erased (see the JLS, Java SE 7 Edition, section 15.12.2.6). In
this case the return type of sampleMethod(Baz) is
java.util.List instead of java.util.List> and thus the
return type of get(int) is Object, which is not assignment-compatible
with Baz.