Why diamond operator is used for Type Inference in Java 7?

Petro Semeniuk picture Petro Semeniuk · Feb 16, 2013 · Viewed 9.8k times · Source

List<String> list = new ArrayList(); will result in compiler warning.

However the following example compiles without any warning: List<String> list = new ArrayList<>();

I'm curious why introducing of diamond operator is needed at all. Why not just have type inference on constructor if type argument is absent (as its already done for static methods in java and exploited by collection libraries like google guava)

EDIT: Using millimoose answer as starting point I looked what type erasure actually is and it's not just removing all type information. Compiler actually does a bit more(copied from official doc):

  • Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
  • Insert type casts if necessary to preserve type safety.
  • Generate bridge methods to preserve polymorphism in extended generic types.

Answer

Patricia Shanahan picture Patricia Shanahan · Feb 16, 2013

The Java developers try very hard to avoid changing the behavior of existing programs. List<String> list = new ArrayList(); does compile, and creates a raw ArrayList. If type inference were applied to it the result would be an ArrayList<String>, changing its behavior and possibly causing run time errors elsewhere in the program.

============================================================================

After further consideration, and a comment by @millimoose, I see that the changes in behavior would be local to the initializer, and detected at compile time. Consider the following program:

import java.util.ArrayList;
import java.util.List;


public class Test {
  public static void main(String[] args) throws Exception {
    List<Integer> integers = new ArrayList<Integer>();
    integers.add(Integer.valueOf(3));
    integers.add(Integer.valueOf(4));
    List<String> list = new ArrayList(integers);
    System.out.println(list);
  }
}

Without type inference, it runs and prints [3, 4], despite the undesirable situation of a List<String> that contains Integer references.

With type inference, it would not compile because the ArrayList(Collection<? extends E> c) does not allow use of a List<Integer> as argument when creating an ArrayList<String>.