Question 11 · Section 13

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.

Language versions: English Russian Ukrainian

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

  1. Immutable typesString, BigDecimal, LocalDate, Integer
  2. Private data — object is created inside the class and never leaves it
  3. Transfer Objects — if the class by design is a mutable DTO
  4. Mutable DTO / Builder pattern — objects are mutable by design
  5. 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() or Arrays.copyOf()
  • Collections: List.copyOf(input) (Java 10+) or new 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.copyOf vs new 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]]