Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When does diamond syntax not work in Java 8?

Tags:

java

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?

like image 256
Louis Wasserman Avatar asked Nov 25 '14 19:11

Louis Wasserman


People also ask

What is the purpose of diamond operator in Java?

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.

Do you know the diamond operator in Java?

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.


1 Answers

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<>()));
  }
}
like image 120
Liam Miller-Cushon Avatar answered Oct 11 '22 04:10

Liam Miller-Cushon