The Diamond Operator (<>)
In the object creation expression of the new operator, the actual type parameter was explicitly specified after the class name—in contrast to the constructor declaration.
Node<String> lst = new Node<String>(“Hi”, null); // Explicit actual type parameter
The actual type parameters can be omitted, but not the angle brackets (<>), if the compiler can infer the actual type parameters from the context of the object creation expression. The angle brackets with no actual parameters (<>) are commonly referred to as the diamond operator.
Node<String> lst = new Node<>(“Hi”, null); // Actual type parameter inferred.
In the object creation expression above, the compiler performs automatic type inference to infer that the actual type parameter in the expression must be String. The compiler is able to infer the actual type parameter from the type information of the constructor call arguments.
new Node<>(null, null); // Actual type parameter: Object.
In the code below, the compiler uses the type information of the variable on the left-hand side to infer the actual type parameter of the object creation expression, thereby ensuring compatibility with the target type on the left-hand side of the assignment.
Node<String> strNode = new Node<>(null, null); // Actual type parameter: String.
Node<Integer> intNode = new Node<>(null, null); // Actual type parameter: Integer.
Node<Number> numNode = new Node<>(null, null); // Actual type parameter: Number.
Node<Number> lstNode = new Node<>(2021, null); // Actual type parameter: Number.
In the last declaration, the int value 2021 is boxed into an Integer object that can be assigned to a reference of its superclass Number. In other words, the signature of the constructor call is Node<Number>(Number, Node<Number>).
Given the following scenario:
// (1) Method declaration with parameterized type as formal parameter.
void find(Node<String> node) { /* … */ }
…
// (2) Method call where actual argument uses diamond operator.
find(new Node<>(null,null)); // Actual type parameter: Object or String?
The compiler takes the target type (Node<String>) in the method declaration into consideration, correctly inferring the actual type parameter to be String, in order for the actual and the formal parameters in the call to be assignment compatible.
A single diamond operator must replace the entire actual type parameter list in the object creation expression. In the first declaration below, the compiler infers that the actual type parameter list is <String, List<Integer>>.
HashMap<String, List<Integer>> map = new HashMap<>();
HashMap<String, List<Integer>> map = new HashMap<String,<>>(); // Error!
If the actual type parameters are not specified and the diamond operator is omitted, the compiler issues an unchecked conversion warning—that is, the code will compile, but all bets are off at runtime. Below, the reference type Node in the object creation expression is interpreted as a raw type. Implications of interoperability between generic types and raw types are discussed on p. 575.
Node<String> rawNode = new Node(“Hi”, null); // Unchecked conversion warning!
The diamond operator can be used to instantiate an anonymous class (see p. 633).
new Node<>(“Hi”, null) {/* … */}; // Parameterized type: Node<String>
new Node(“Hi”, null) {/* … */}; // Raw type: Node
Leave a Reply