Guide to the Diamond Operator in Java – Java中的钻石运算符指南

最后修改: 2017年 9月 19日

1. Overview


In this article, we’ll look at the diamond operator in Java and how generics and the Collections API influenced its evolution.


2. Raw Types


Prior to Java 1.5, the Collections API supported only raw types – there was no way for type arguments to be parameterized when constructing a collection:

在Java 1.5之前,集合API只支持原始类型–在构造一个集合时,没有办法将类型参数参数化。

List cars = new ArrayList();
cars.add(new Object());
cars.add(new Integer(1));

This allowed any type to be added and led to potential casting exceptions at runtime.


3. Generics


In Java 1.5, Generics were introduced – which allowed us to parameterize the type arguments for classes, including those in the Collections API – when declaring and constructing objects:

在Java 1.5中,引入了泛型–它允许我们在声明和构造对象时对类的类型参数进行参数化,包括集合API中的类型参数。

List<String> cars = new ArrayList<String>();

At this point, we have to specify the parameterized type in the constructor, which can be somewhat unreadable:


Map<String, List<Map<String, Map<String, Integer>>>> cars 
 = new HashMap<String, List<Map<String, Map<String, Integer>>>>();

The reason for this approach is that raw types still exist for the sake of backward compatibility, so the compiler needs to differentiate between these raw types and generics:


List<String> generics = new ArrayList<String>();
List<String> raws = new ArrayList();

Even though the compiler still allows us to use raw types in the constructor, it will prompt us with a warning message:


ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized

4. Diamond Operator


The diamond operator – introduced in Java 1.7 – adds type inference and reduces the verbosity in the assignments – when using generics:

钻石运算符–在Java 1.7中引入–增加了类型推理并减少了赋值中的冗长性–当使用泛型时

List<String> cars = new ArrayList<>();

The Java 1.7 compiler’s type inference feature determines the most suitable constructor declaration that matches the invocation.

Java 1.7编译器的类型推理功能确定了与调用相匹配的最合适的构造函数声明

Consider the following interface and class hierarchy for working with vehicles and engines:


public interface Engine { }
public class Diesel implements Engine { }
public interface Vehicle<T extends Engine> { }
public class Car<T extends Engine> implements Vehicle<T> { }

Let’s create a new instance of a Car using the diamond operator:


Car<Diesel> myCar = new Car<>();

Internally, the compiler knows that Diesel implements the Engine interface and then is able to determine a suitable constructor by inferring the type.


5. Conclusion


Simply put, the diamond operator adds the type inference feature to the compiler and reduces the verbosity in the assignments introduced with generics.


Some examples of this tutorial can be found on the GitHub project, so feel free to download it and play with it.