The main difference between Java?7 and Java?8 is the target type inference. While Java?7 only considers the parameters of a method invocation to determine the type arguments, Java?8 will use the target type of an expression, i.e. the parameter type in case of a nested method invocation, the type of the variable that is initialized or assigned to, or the method’s return type in case of a return
statement.
E.g. when writing, List<Number> list=Arrays.asList(1, 2, 3, 4);
, Java?7 will infer the type List<Integer>
for the right hand side by looking at the method’s arguments and generate an error while Java?8 will use the target type List<Number>
to infer the constraint that the method arguments must be instances of Number
which is the case. Therefore, it is legal in Java?8.
If you are interested in the formal details, you may study the “Java Language Specification, Chapter 18. Type Inference”, especially §18.5.2. Invocation Type Inference, however, that’s not easy reading…
So what happens when you say Enum foo = null; tryCompile(EnumSet.of(foo));
?
In Java?7 the type of the expression EnumSet.of(foo)
will be inferred by looking at the type of the argument, foo
which is the raw type Enum
, hence an unchecked operation will be performed and the result type is the raw type EnumSet
. This type implements the raw type Iterable
and hence can be passed to tryCompile
forming another unchecked operation.
In Java?8 the target type of EnumSet.of(foo)
is the type of the first parameter of tryCompile
which is Iterable<C extends Enum<C> & Another>
, so without going too much into details, in Java?7 EnumSet.of
will be treated as raw type invocation because it has a raw type argument, in Java?8 it will be treated as generic invocation because it has a generic target type. By treating it as as a generic invocation, the compiler will conclude that the type found (Enum
) is not compatible to the required type C extends Enum<C> & Another
. While you could get away with assigning the raw type Enum
to C extends Enum<C>
with an unchecked warning, it will considered to be incompatible with Another
(without a type-cast).
You can indeed insert such a cast:
Enum foo = null;
tryCompile(EnumSet.of((Enum&Another)foo));
This compiles, of course not without an unchecked warning due to the assignment of Enum
to C?extends?Enum<C>
.
You can also dissolve the target type relationship so that the same steps as in Java?7 are performed:
Enum foo = null;
EnumSet set = EnumSet.of(foo);
tryCompile(set);
Here, raw types are used throughout the three lines so this compiles with unchecked warnings and the same ignorance about the implements Another
constraint as in Java?7.