How to protect a collection from modification?
In Java, there are several ways to protect a collection:
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()orCollections.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()orCollections.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 nullList.of()— creates a copy, no link, null prohibited, for constantsList.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.ofvsList.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]]