When should you make a defensive copy?
A defensive copy should be made when your class receives or gives out mutable data from/to someone.
Basic Level
A defensive copy should be made when your class receives or gives out mutable data from/to someone.
When to make a copy
1. When receiving data (in the constructor)
// For a fully immutable class there are no setters.
// This example shows the Builder pattern or constructor with copying:
public class MyClass {
private final List<String> items;
public MyClass(List<String> items) {
this.items = new ArrayList<>(items); // defensive copy in constructor
}
}
2. When returning data (in the getter)
public List<String> getItems() {
return new ArrayList<>(items); // copy of outgoing data
}
When you DON’T need to make a copy
- Primitives (
int,boolean) — they are immutable String— immutable- Internal data that never leaves the class
Intermediate Level
Main scenarios
A. Arrays
public class MyClass {
private final int[] numbers;
public MyClass(int[] numbers) {
this.numbers = numbers.clone(); // or Arrays.copyOf(numbers)
}
public int[] getNumbers() {
return numbers.clone();
}
}
B. Collections
this.list = List.copyOf(input); // Java 10+
this.list = new ArrayList<>(input); // Java 8
C. Date
this.date = new Date(date.getTime());
When copying is NOT needed
- Immutable types —
String,BigDecimal,LocalDate,Integer - Private data — object is created inside the class and never leaves it
- Transfer Objects — if the class by design is a mutable DTO
- Mutable DTO / Builder pattern — objects are mutable by design
- Primitives and wrappers (int, Integer, String) — immutable by nature
Copy vs Unmodifiable
- In the constructor — only Copy (
new ArrayList(original)) - In the getter — can be Copy or Unmodifiable (
Collections.unmodifiableList(original))
// List.copyOf throws NPE on null elements, new ArrayList — allows them.
Advanced Level
TOCTOU and operation ordering
Copy before validation:
public SecureConfig(Map<String, String> config) {
Map<String, String> copy = new HashMap<>(config); // copy first
if (!copy.containsKey("auth")) throw new IllegalStateException(); // then check
this.config = Map.copyOf(copy);
}
Without this, in a multi-threaded environment, the map may change after the check but before the save.
Performance
List.copyOf()— optimized in JDK 10+, may return the same object if the input is already immutable- For large collections in hot loops, consider persistent data structures (Vavr)
- Avoid deep copying of huge object graphs
Summary for Advanced
- Copy everything that can be changed from outside
- Copy first, then validate
- Use
List.copyOf()for modern defensive copying - Don’t copy huge arrays in “hot” loops without necessity
- Distinguish wrapper and copy: wrapper doesn’t protect from changes to the original
Interview Cheat Sheet
Must know:
- Copy when receiving (constructor) and when returning (getter) mutable data
- NO need to copy: primitives, String, LocalDate, Integer, private data
- Arrays:
numbers.clone()orArrays.copyOf() - Collections:
List.copyOf(input)(Java 10+) ornew ArrayList<>(input)(Java 8) - Date:
new Date(date.getTime()) - Copy vs Unmodifiable: in constructor — only Copy, in getter — Copy or Unmodifiable
- TOCTOU: copy first, then validate
Frequent follow-up questions:
- When is copying NOT needed? — Immutable types, private data, Transfer Objects
List.copyOfvsnew ArrayList?* — List.copyOf returns immutable; new ArrayList — mutable- What if the collection is huge? — Consider persistent structures (Vavr) or COW
- Does List.copyOf allow null? — No, throws NPE; new ArrayList allows it
Red flags (DO NOT say):
- “Defensive copy is needed for all types” — primitives and String don’t need it
- “You can mutate a mutable key in HashMap” — the object gets lost in the bucket
- “UnmodifiableList in constructor — protection” — it’s a wrapper, not a copy
- “Copying after validation — safe” — TOCTOU attack is possible
Related topics:
- [[9. What to do if a class field references a mutable object]]
- [[10. What is a defensive copy]]
- [[12. How to protect a collection from modification]]
- [[13. What is Collections.unmodifiableList() and how does it work]]
- [[29. How to properly work with collections in immutable classes]]