Question 10 · Section 13

What is a defensive copy?

A Defensive Copy is creating a copy of data to protect the internal object from external modifications.

Language versions: English Russian Ukrainian

Basic Level

A Defensive Copy is creating a copy of data to protect the internal object from external modifications.

Like a photocopy of a document: you hand out a copy, and if someone writes on it, your original is unaffected.

Simple example

public class MyClass {
    private Date date;

    public MyClass(Date date) {
        // BAD: this.date = date; // external variable can change
        // GOOD:
        this.date = new Date(date.getTime()); // created a copy
    }

    public Date getDate() {
        return new Date(date.getTime()); // return a copy
    }
}

Why this is needed

Without a copy, the calling code can change your internal data through the reference:

Date d = new Date();
MyClass obj = new MyClass(d);
d.setYear(2000); // Changed MyClass's internal object!

When NOT to make a defensive copy

  1. Immutable types (String, Integer, LocalDate) — copying is pointless
  2. Fully controlled internal API — caller guaranteed not to mutate
  3. Performance-critical code — copying on every call creates unacceptable overhead

Intermediate Level

Two points of protection

1. In the constructor (data input)

public class MyObject {
    private final Date startDate;
    private final List<String> items;

    public MyObject(Date date, List<String> items) {
        this.startDate = new Date(date.getTime());
        this.items = new ArrayList<>(items);
    }
}

2. In the getter (data output)

public Date getStartDate() {
    return new Date(startDate.getTime());
}

public List<String> getItems() {
    return Collections.unmodifiableList(new ArrayList<>(items));
}

Shallow vs Deep Copy

  • Shallow Copy — the container is copied, but elements remain the same
    List<String> copy = new ArrayList<>(original);
    
  • Deep Copy — all nested objects are recursively copied
    List<User> copy = original.stream()
        .map(u -> new User(u.getName(), u.getAge()))
        .toList();
    

Modern approach (Java 10+)

this.items = List.copyOf(items); // immutable copy

Advanced Level

TOCTOU and operation ordering

Copy before validation:

public SecureClass(List<String> roles) {
    List<String> copy = new ArrayList<>(roles); // 1. Copy
    if (copy.contains("admin")) {               // 2. Check
        // ...
    }
    this.roles = List.copyOf(copy);             // 3. Save
}

Otherwise a TOCTOU attack is possible: data changes between the check and the use.

Wrapper vs Copy

Collections.unmodifiableList(original) is a wrapper, not a copy. If original changes, the wrapper changes too. Use only for returning from a getter, but not in the constructor.

Performance

Defensive copying is an O(n) operation. In high-load systems:

  • Avoid copying in hot loops
  • Use persistent structures (Vavr) for structural sharing
  • Caching copies is only safe if the data is truly static; otherwise you risk returning stale data.

Summary for Advanced

  • Defensive copy — creating a “snapshot” of mutable data
  • Mandatory condition for immutability when there are object fields
  • Always make a copy before validation
  • Collections.unmodifiableList() — a wrapper, not a copy; use List.copyOf() for true protection

Interview Cheat Sheet

Must know:

  • Defensive Copy — creating a copy of data to protect from external changes
  • Two points of protection: constructor (input) and getter (output)
  • Shallow Copy — container is copied, Deep Copy — all nested objects recursively
  • TOCTOU: copy BEFORE validation, otherwise data changes between check and use
  • Wrapper vs Copy: unmodifiableList — wrapper (O(1)), List.copyOf — copy (O(n))
  • When NOT to make: immutable types, internal API, performance-critical code

Frequent follow-up questions:

  • What’s cheaper — wrapper or copy? — Wrapper O(1), copy O(n); but wrapper doesn’t protect from changes to the original
  • When is shallow copy sufficient? — When the collection contains immutable objects (String, Integer)
  • What is a TOCTOU attack? — Data changes between the check and the copy
  • List.copyOf vs new ArrayList? — List.copyOf returns an immutable list; new ArrayList — mutable

Red flags (DO NOT say):

  • “UnmodifiableList is a copy” — it’s a wrapper, changes to the original are visible
  • “Defensive copy is always needed” — pointless for immutable types
  • “clone() is a reliable way” — clone() is considered broken (Effective Java Item 13)
  • “Copying after validation — correct” — you need to COPY BEFORE validation

Related topics:

  • [[8. Is it enough to make all fields final for immutability]]
  • [[9. What to do if a class field references a mutable object]]
  • [[11. When should you make a defensive copy]]
  • [[12. How to protect a collection from modification]]
  • [[14. What is the difference between shallow copy and deep copy]]