skip to content

What are the null-element and duplicate-element rules of List.of / Set.of / Map.of, and how do they differ from ArrayList/HashSet/HashMap?

level: middleimportance: should knowfreq 58%

answer

  1. Null anywhere -> NPE (all three factories)
  2. Set.of duplicate / Map.of duplicate key -> IllegalArgumentException
  3. List.of CAN hold duplicate values
  4. Classic collections allow one null + silently dedupe/overwrite
  5. Strictness = fail fast for fixed data

basics

~20 s

The factory methods refuse nulls: any null element, key, or value throws NullPointerException. Set.of and Map.of also throw IllegalArgumentException if you pass duplicate elements or duplicate keys. Standard ArrayList/HashSet/HashMap allow one null and silently ignore duplicates.

solid answer

~50 s

Factory collections are deliberately strict. Null is rejected everywhere: a null element in List.of/Set.of, or a null key or value in Map.of, throws NullPointerException at construction. They are also intolerant of accidental duplicates that signal a bug: Set.of with a repeated element and Map.of with a repeated key throw IllegalArgumentException — they fail fast rather than silently collapsing. This contrasts with the classic collections: ArrayList allows multiple nulls; HashSet allows a single null and just ignores a duplicate add; HashMap allows one null key, null values, and silently overwrites on a duplicate key. The strictness exists because immutable, shared, fixed data should expose construction-time mistakes immediately, and disallowing null lets the implementations be more compact and avoids the ambiguity null introduces. If you genuinely need nulls or want last-write-wins semantics, use the traditional collections instead.

code

java · 11 lines
java
List.of("a", "a");           // OK - lists allow duplicates
Set.of("x", "x");            // IllegalArgumentException - duplicate element
Map.of("k", 1, "k", 2);      // IllegalArgumentException - duplicate key

List.of("a", null);          // NullPointerException
Map.of("k", null);           // NullPointerException (null value)
Map.of(null, "v");           // NullPointerException (null key)

// Classic collections stay silent:
Set<String> s = new HashSet<>();
s.add("x"); s.add("x");       // second ignored, no error

go deeper

for a junior

Knows factories reject null and that the result cannot be changed.

for a middle

Distinguishes NPE for nulls from IllegalArgumentException for Set/Map duplicates, and contrasts with lenient HashSet/HashMap behavior.

for a senior

Explains the fail-fast rationale and when null/duplicate tolerance means choosing classic collections instead.

for a principal

Uses these guarantees in API contracts and validation strategy; reasons about null-hostility as a design choice across the codebase.

## Background terms - *Element*: a value stored in a `List` or `Set`. - *Key/value*: in a `Map`, each entry is a key (the lookup handle) mapped to a value. - *Duplicate*: in a `Set`, two elements that are `equals()`; in a `Map`, two entries with `equals()` keys. - *NullPointerException (NPE)*: thrown when code uses a `null` where an object is required. - *IllegalArgumentException (IAE)*: thrown when a method receives an argument that is invalid for it. - *Fail fast*: detect and report a problem at the earliest possible moment (here, at construction) instead of letting it silently corrupt later behavior. ## The classic collections are lenient ```java List<String> a = new ArrayList<>(); a.add(null); a.add(null); // fine: two nulls allowed Set<String> s = new HashSet<>(); s.add("x"); s.add("x"); // second add ignored, no error s.add(null); // one null allowed Map<String,String> m = new HashMap<>(); m.put("k", "1"); m.put("k", "2"); // silently overwrites: k -> 2 m.put(null, "v"); // one null key allowed ``` Nothing throws. Duplicates and nulls are tolerated. ## The factory collections are strict ```java List.of("a", null); // NullPointerException Set.of("x", "x"); // IllegalArgumentException: duplicate element Map.of("k", "1", "k", "2"); // IllegalArgumentException: duplicate key Map.of("k", null); // NullPointerException Map.of(null, "v"); // NullPointerException ``` Every rule is enforced *at the moment you build the collection*. ## Why the strictness 1. **Bug surfacing.** These collections are meant for small, fixed, often-shared data. A duplicate in a literal `Set.of(...)` almost always means a typo. Failing fast turns a silent logic bug into an immediate, obvious exception. 2. **No-null simplicity.** Forbidding null removes a whole class of ambiguity ("does this set contain null or is the value absent?") and lets the compact internal implementations skip null bookkeeping. 3. **Immutability fit.** Because the collection can never change after creation, the only chance to catch a bad input is at construction — so they check thoroughly there. ## A subtle point: List.of allows value-duplicates A `List` is *allowed* to contain duplicates by definition, so `List.of("a", "a")` is perfectly legal — only `Set.of` and `Map.of` (keys) reject duplicates. The null rule, however, applies to all three. ## When to avoid the factories If your data legitimately needs `null` (e.g., a list with intentional gaps) or you want last-write-wins map semantics, use `ArrayList`/`HashMap` (optionally wrapped) instead. The factories are the wrong tool when null or duplicate-tolerance is a feature.

  • Does List.of("a", "a") throw?
    No. A List may contain duplicate values, so this is allowed. Only Set.of (duplicate element) and Map.of (duplicate key) throw IllegalArgumentException.
  • What exception does Map.of("k", null) throw and when?
    NullPointerException, thrown immediately at construction, because null values are not permitted in factory maps.

saying these in an interview costs you the question

  • Thinking Set.of("x","x") silently dedupes like HashSet
  • Assuming Map.of overwrites on duplicate key (it throws)
  • Believing List.of forbids duplicate values (it allows them)
  • Expecting null to be allowed in any factory

context