Question 12 · Section 13

How to protect a collection from modification?

In Java, there are several ways to protect a collection:

Language versions: English Russian Ukrainian

Basic Level

In Java, there are several ways to protect a collection:

Method 1: Collections.unmodifiableList()

List<String> original = new ArrayList<>();
original.add("A");
List<String> readOnly = Collections.unmodifiableList(original);

readOnly.add("B"); // Throws UnsupportedOperationException!

But if you change original, the changes will be visible through readOnly.

Method 2: List.of() — Java 9+

List<String> immutable = List.of("A", "B", "C");
immutable.add("D"); // UnsupportedOperationException!

Method 3: List.copyOf() — Java 10+

List<String> original = new ArrayList<>();
original.add("A");
List<String> immutable = List.copyOf(original); // creates a copy

When collection protection is NOT needed

  • Private collections that never leave the class
  • Read-only reference data loaded once at startup
  • Internal buffers used only for computations

Intermediate Level

Comparison of approaches

Method Makes a copy? Link to original Null elements
Collections.unmodifiableList() No Live link Allowed
new ArrayList(original) Yes No link Allowed
List.of() Yes No link Prohibited
List.copyOf() Yes No link Prohibited

Example of “live link” with unmodifiableList:

List<String> original = new ArrayList<>(List.of("A", "B"));
List<String> unmod = Collections.unmodifiableList(original);
original.add("C");
System.out.println(unmod); // [A, B, C] — unmodifiableList sees changes to original!

List.copyOf may return the same object if the passed collection is already immutable. This is a JDK optimization — no extra copy is created.

When to use what

  • Return from getter: List.copyOf() or Collections.unmodifiableList()
  • In constructor: List.copyOf() (creates an independent copy)
  • Constants: List.of() (optimized immutable collection)

Protecting Map and Set

Map<String, Integer> immutableMap = Map.copyOf(originalMap);
Set<String> immutableSet = Set.copyOf(originalSet);

Important: shallow protection

All these methods provide only Shallow protection — if the objects in the list are mutable, their state can be changed:

List<User> users = List.copyOf(userList);
// users cannot be changed, but:
users.get(0).setName("New Name"); // POSSIBLE!

Advanced Level

UnmodifiableList under the hood

Collections.unmodifiableList() uses the Decorator pattern. The internal class UnmodifiableList:

  • Delegates reading to the original
  • Blocks writing (UnsupportedOperationException)
  • The iterator is also wrapped — remove() is blocked

Creation time: O(1), since no copy is created.

List.copyOf under the hood

List.copyOf() creates a new collection of type ImmutableCollections.ListN:

  • Optimized for memory (no expansion fields)
  • If the input is already immutable — returns it as-is (optimization)
  • Creation time: O(n)

Deep protection

For full immutability of mutable objects in a collection:

  • Use the Vavr library (persistent structures)
  • Or manual deep cloning of each element

Summary for Advanced

  • For returning data — List.copyOf() or Collections.unmodifiableList()
  • For constants — List.of() (Java 9+)
  • All standard JDK means — only Shallow Immutability
  • For guaranteed immutability of the entire structure — Vavr or deep cloning

Interview Cheat Sheet

Must know:

  • 3 main methods: Collections.unmodifiableList(), List.of(), List.copyOf()
  • unmodifiableList — wrapper (O(1)), not a copy, link to original, allows null
  • List.of() — creates a copy, no link, null prohibited, for constants
  • List.copyOf() — creates a copy, no link, null prohibited, optimized (may return the same object)
  • Shallow protection: if objects in the list are mutable, they can be changed via get(0).setName()
  • For Map/Set: Map.copyOf(), Set.copyOf()

Frequent follow-up questions:

  • What’s better — unmodifiableList or List.copyOf? — unmodifiableList for returning from getter (if original is inaccessible), List.copyOf for constructor
  • Does List.copyOf copy if the input is already immutable? — No, returns the same object (JDK optimization)
  • How to protect mutable elements in a list? — Deep Copy: clone each element
  • List.of vs List.copyOf? — List.of for literals/constants, List.copyOf for copying an existing collection

Red flags (DO NOT say):

  • “UnmodifiableList — full protection” — it’s a wrapper, the original can be changed
  • “List.copyOf allows null” — throws NPE
  • “If the container is immutable, elements are too” — no, mutable elements can be changed
  • “unmodifiableList is thread-safe” — no, only immutability, not thread-safety

Related topics:

  • [[10. What is a defensive copy]]
  • [[11. When should you make a defensive copy]]
  • [[13. What is Collections.unmodifiableList() and how does it work]]
  • [[14. What is the difference between shallow copy and deep copy]]
  • [[29. How to properly work with collections in immutable classes]]