As of Java 7, diamond syntax did not always work in method arguments, e.g. Why does the diamond operator not work for java.util.Collections methods in Java 7? . The answer to that question mentions that target type inference in Java 8 fixes that issue.
Are there any remaining cases where diamond syntax cannot be used?
Diamond Operator: Diamond operator was introduced in Java 7 as a new feature. The main purpose of the diamond operator is to simplify the use of generics when creating an object. It avoids unchecked warnings in a program and makes the program more readable.
The diamond operator – introduced in Java 1.7 – adds type inference and reduces the verbosity in the assignments – when using generics: List<String> cars = new ArrayList<>(); The Java 1.7 compiler's type inference feature determines the most suitable constructor declaration that matches the invocation.
The diamond operator cannot always be used in Java 8. The original plan to improve inference in Java 8 (JEP 101) had two goals:
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<>()));
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With