The diamond operator cannot always be used in Java 8. The original plan to improve inference in Java 8 (JEP 101) had two goals:
- Add support for method type-parameter inference in method context
- Add support for method type-parameter inference in chained calls
Only the first was implemented. Borrowing the example from the JEP, consider the following class:
class List<E> {
static <Z> List<Z> cons(Z head, List<Z> tail) { ... };
E head() { ... }
}
In Java 8, the improved method context inference allows the following to compile. With Java 7, it would fail with the error expected List<Integer>, found List<Object>
List<Integer> l = List.cons(42, new List<>());
However, examples that require inference of chained calls still don't work with Java 8:
Integer i = new List<>().head();
Section D of JSR 335 includes a hint about why chained expression inference was abandoned for Java 8:
There has been some interest in allowing inference to "chain": in a().b(), passing type information from the invocation of b to the invocation of a. This adds another dimension to the complexity of the inference algorithm, as partial information has to pass in both directions; it only works when the erasure of the return type of a() is fixed for all instantiations (e.g. List). This feature would not fit very well into the poly expression model, since the target type cannot be easily derived; but perhaps with additional enhancements it could be added in the future.
There are also some more contrived examples where diamond can't be used.
If bugs count, this doesn't compile with javac prior to jdk8u25. (see JDK-8029002)
class Test {
class C<T extends C<T>> {}
void m() {
C<?> i = new C<>();
}
}
error: incompatible types: cannot infer type arguments for Test.C<>
C<?> i = new C<>();
^
reason: inferred type does not conform to upper bound(s)
inferred: Test.C<CAP#1>
upper bound(s): Test.C<Test.C<CAP#1>>,Test.C<CAP#1>
where CAP#1 is a fresh type-variable:
CAP#1 extends Test.C<CAP#1> from capture of ?
There's also a performance issue (JDK-8051946) with the new type inference implementation that can affect code using the diamond operator. The following example takes minutes to compile if the diamond operator is used.
class Test {
<T> T and(T a, T b) { return null; }
class C<T> {}
void g(String s) {}
void g(Object s) {}
void m() {
g(
and(
and(
and(
and(
and(
and(
and(new C<>(),
new C<>()),
new C<>()),
new C<>()),
new C<>()),
new C<>()),
new C<>()),
new C<>()));
}
}