skip to content

Immutable Factory Methods

List.of, Set.of and Map.of build genuinely immutable collections that reject nulls and throw on any mutation. Interviewers contrast them with Collections.unmodifiableList, which only wraps a list someone else can still change.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

5

What are the Java 9+ List.of, Set.of, and Map.of factory methods, and why were they introduced?

level: juniorimportance: must knowfreq 72%

answer

  1. Java 9 static factories on the interfaces
  2. One-line immutable List/Set/Map
  3. Mutation throws UnsupportedOperationException
  4. Nulls rejected with NPE
  5. 0–10 overloads + varargs

basics

~10 s

They are static methods added in Java 9 that build small, unchangeable collections in one line, like List.of(1, 2, 3). The returned collection cannot be added to, removed from, or modified.

solid answer

~40 s

List.of, Set.of, and Map.of are static factory methods introduced in Java 9 to create compact, immutable collections concisely. Before them, building a fixed collection meant several lines (new ArrayList, repeated add calls, often wrapped in Collections.unmodifiableList). The factories collapse that to one expression: List.of("a", "b"). The returned instances are truly immutable: any mutating operation (add, remove, set, put, clear) throws UnsupportedOperationException. They also reject null elements, keys, and values, throwing NullPointerException. They have overloads for 0 to 10 elements plus a varargs version, and the implementations are memory-optimized for small sizes. They are ideal for constants, default values, and small literal data where the contents never change.

code

java · 7 lines
java
List<String> roles = List.of("ADMIN", "USER");
Set<Integer> primes = Set.of(2, 3, 5, 7);
Map<String, Integer> ages = Map.of("Ann", 30, "Bob", 25);

// All of these throw at runtime:
// roles.add("GUEST");        -> UnsupportedOperationException
// List.of("a", null);        -> NullPointerException

go deeper

for a junior

Knows the methods exist, can create a List/Set/Map in one line, and knows the result cannot be modified.

for a middle

Explains immutability vs unmodifiable wrappers, the null rejection, and unspecified ordering of Set/Map.of.

for a senior

Discusses the 0–10 overloads/memory layout, when to use factories vs builders, and thread-safety benefits of immutability.

for a principal

Frames immutable collections in API-design terms: returning them from public methods to prevent caller mutation, defensive copying tradeoffs, and team conventions.

## What a collection is A *collection* in Java is an object that holds a group of other objects. `List` is an ordered sequence (allows duplicates), `Set` is a group with no duplicates, and `Map` is a set of key→value pairs. These are *interfaces* — contracts that many concrete classes (like `ArrayList`, `HashSet`, `HashMap`) implement. ## The problem before Java 9 To create a small, fixed list you had to write several statements: ```java List<String> list = new ArrayList<>(); list.add("a"); list.add("b"); ``` If you wanted it to be *unchangeable*, you wrapped it: `Collections.unmodifiableList(list)`. That is verbose and error-prone. `Arrays.asList("a", "b")` was shorter but produced a fixed-size list that still allowed `set()` (replacing an element) and was backed by the original array. ## What the factory methods are Java 9 added *static factory methods* directly on the interfaces: - `List.of(...)` returns an immutable `List`. - `Set.of(...)` returns an immutable `Set`. - `Map.of(k1, v1, k2, v2, ...)` returns an immutable `Map`, and `Map.entry(k, v)` plus `Map.ofEntries(...)` handles larger maps. A *static factory method* is just a static method that returns an instance — you call it on the type itself (`List.of(...)`), not with `new`. ## Key properties 1. **Immutable.** Once created, the contents cannot change. Calling `add`, `remove`, `set`, `put`, or `clear` throws `UnsupportedOperationException` — an exception meaning "this operation is not allowed here." 2. **Null-hostile.** Passing `null` as an element, key, or value throws `NullPointerException`. The traditional `ArrayList`/`HashMap` allow nulls. 3. **Compact.** There are explicit overloads for 0–10 elements (so no array is allocated for small sizes) and a varargs fallback for more. 4. **Unspecified iteration order** for `Set.of` and `Map.of` — and the order can even differ between JVM runs, on purpose, so you don't accidentally depend on it. ## Why introduced The motivation was *convenience and safety*: a one-line way to build the small, never-changing collections that appear constantly in real code (configuration defaults, allowed-value sets, lookup tables) while guaranteeing nobody can mutate them by accident. Immutable data is also easier to reason about and safe to share between threads. ## Example ```java List<String> roles = List.of("ADMIN", "USER"); Set<Integer> primes = Set.of(2, 3, 5, 7); Map<String, Integer> ages = Map.of("Ann", 30, "Bob", 25); ``` Each of these is fully built, immutable, and rejects nulls.

  • What happens if you call add() on a List.of result?
    It throws UnsupportedOperationException, because the returned list is immutable and supports no mutating operations.
  • Can you put a null into Map.of?
    No. A null key or value throws NullPointerException immediately when the map is created.

saying these in an interview costs you the question

  • Thinking List.of returns a mutable ArrayList you can add to
  • Confusing it with Arrays.asList (which allows set())
  • Believing nulls are allowed as elements

context

open as a page

How do List.of / Set.of / Map.of differ from Collections.unmodifiableList / unmodifiableSet / unmodifiableMap?

level: middleimportance: must knowfreq 74%

basics

~20 s

The factory methods create a brand-new collection that is truly immutable and copies nothing live. The Collections.unmodifiable* methods only wrap an existing collection in a read-only view, so if the original changes, the view changes too.

open as a page

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%

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.

open as a page

Why do List.of / Set.of / Map.of have many fixed-arity overloads plus a varargs form, and how do you build a larger immutable Map?

level: seniorimportance: should knowfreq 42%

basics

~20 s

They provide overloads for 0 to 10 elements so small collections avoid creating an array, which saves memory and speeds things up. For bigger collections there is a varargs version, and for large maps you use Map.entry plus Map.ofEntries.

open as a page

Are collections from List.of / Map.of deeply immutable, and what does that mean for stored mutable objects and thread safety?

level: seniorimportance: should knowfreq 48%

basics

~20 s

They are only shallowly immutable. You cannot add, remove, or replace elements, but if an element is itself a mutable object (like an ArrayList or a bean), you can still change that object's internal state. The collection structure is fixed; the contents' internals are not protected.

open as a page