🧪 Generics · Intermediate

Diamond operator in Java

new ArrayList<>() infers type arguments.

🧩 The mysteryMap<String, List<Integer>> scores = new HashMap<String, List<Integer>>(); Saying everything twice is tiring. Java 7 gave us two characters that fix it, plus one trap with var.

Say it once

Since Java 7, the **diamond <> tells the compiler: infer the type arguments from the context**, usually the variable's declared type.

Map<String, List<Integer>> scores =
    new HashMap<>();  // <String, List<Integer>>
List<String> names = new ArrayList<>();

<> vs nothing at all

✗ Raw type
List<String> l = new ArrayList();

No <> at all creates a raw ArrayList: unchecked warnings, and the compiler stops checking element types.

✓ Diamond
List<String> l = new ArrayList<>();

The diamond infers <String>: fully type-checked, no repetition.

var + diamond = Object

The diamond infers from the left-hand side. With var, there is no left-hand type, so the compiler falls back to **ArrayList<Object>**.

var list = new ArrayList<>();
// list is ArrayList<Object>
🔮 Predict it

Your turn

What does this print?

var list = new ArrayList<>();
list.add(3);
list.add("three");
System.out.println(list);
  1. Compile error
  2. [3, three]
  3. Throws ClassCastException
Show the answer

list is an ArrayList<Object>. An Integer and a String are both Objects, so both adds compile and it prints [3, three].

🔮 Predict it

Use what you stored

Now try to use the String. What happens?

var list = new ArrayList<>();
list.add("hey");
System.out.println(list.get(0).toUpperCase());
  1. Prints HEY
  2. Compile error
  3. Throws ClassCastException
Show the answer

For an ArrayList<Object>, get(0) returns **Object**, and Object has no toUpperCase(). Compile error, even though the element really is a String.

Pick one side for the type

Write the type once, on one side: either on the left with a diamond on the right, or with var on the left and the full type on the right. Since Java 9, the diamond also works with anonymous classes.

List<String> a = new ArrayList<>();   // ✓
var b = new ArrayList<String>();      // ✓
var c = new ArrayList<>();            // Object!
💼 In the real world

In code review

new HashMap<>() is everywhere in modern Java. Reviewers flag two smells: a missing <> (an accidental raw type, which triggers "unchecked" warnings) and var x = new ArrayList<>(), which quietly makes a list of Object.

Key takeaways

  1. List<String> l = new ArrayList<>(); // infers <String>
  2. new ArrayList() without <> is a raw type — not the same thing
  3. var l = new ArrayList<>(); // ArrayList<Object>
  4. Since Java 9 the diamond also works with anonymous classes
🤯 Did you know?

The <> was nicknamed "diamond" for its shape. It arrived in Java 7 as part of Project Coin, a bundle of small language improvements that also brought try-with-resources and strings in switch.

Practice questions

Pick the shortest correct way to complete the line.

Map<String, List<Integer>> scores =
    new HashMap___();
  1. <>
  2. <?, ?>
  3. <String>
  4. []
Check your answer

<>. The diamond infers <String, List<Integer>>. <String> has the wrong number of arguments, and you can't instantiate a wildcard type like HashMap<?, ?>.

What is the difference between new ArrayList<>() and new ArrayList()?

  1. None — both infer the type
  2. The first infers type arguments; the second creates a raw type and loses generic type checks
  3. The second is faster because it skips generics
  4. The first only works for Strings
Check your answer

The first infers type arguments; the second creates a raw type and loses generic type checks. Leaving out <> entirely makes a raw ArrayList, which produces unchecked warnings and lets wrong types slip in.

Next: how do you write a method that works for any kind of number, but refuses Strings?