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?
answer
- Null anywhere -> NPE (all three factories)
- Set.of duplicate / Map.of duplicate key -> IllegalArgumentException
- List.of CAN hold duplicate values
- Classic collections allow one null + silently dedupe/overwrite
- Strictness = fail fast for fixed data
basics
~20 sThe 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 sFactory 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 linesList.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 errorgo deeper
Knows factories reject null and that the result cannot be changed.
Distinguishes NPE for nulls from IllegalArgumentException for Set/Map duplicates, and contrasts with lenient HashSet/HashMap behavior.
Explains the fail-fast rationale and when null/duplicate tolerance means choosing classic collections instead.
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