How do you create immutable/unmodifiable collections in Java?

8 minintermediateimmutabilitycollectionsjava9

Quick Answer

List.of()/Set.of()/Map.of() (Java 9+) create truly immutable collections that throw UnsupportedOperationException on any mutation attempt, and also reject null elements. Collections.unmodifiableList(list) (and similar) instead wrap an existing mutable collection in a read-only view — the view itself can't be modified, but changes to the underlying collection still show through it.

Detailed Answer

There are two distinct approaches, and they behave differently:

1. List.of(...), Set.of(...), Map.of(...) (Java 9+): create genuinely immutable collections. Any mutation attempt (add, remove, set) throws UnsupportedOperationException, and they reject null elements/keys/values outright (throwing NullPointerException at creation time).

List<String> l = List.of("a", "b", "c");
l.add("d"); // UnsupportedOperationException
List.of("a", null); // NullPointerException immediately

2. Collections.unmodifiableList(list) (and unmodifiableSet, unmodifiableMap, ...): wraps an existing mutable collection in a read-only view. The view itself rejects direct mutation, but it is not truly immutable — if code still holds a reference to the original mutable list and modifies it, those changes are visible through the wrapper, since it's just a thin delegating façade, not a copy.

List<String> mutable = new ArrayList<>(List.of("a", "b"));
List<String> view = Collections.unmodifiableList(mutable);
mutable.add("c");
view.get(2); // "c" — the wrapper sees the underlying change

Rule of thumb: prefer List.of()/Set.of()/Map.of() for genuinely fixed data (constants, defensive copies to hand out to callers); use Collections.unmodifiableX mainly when you need to expose a read-only view over a collection you still intend to mutate internally.

Related Resources