Fail-Fast vs Fail-Safe Iterators

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 5 min

TL;DR

  • Fail-Fast: Throws a ConcurrentModificationException immediately if the collection is structurally modified while iterating over it (e.g., ArrayList, HashMap).
  • Fail-Safe (Weakly Consistent): Does not throw an exception if the collection is modified. It works on a clone of the collection or handles concurrency internally (e.g., ConcurrentHashMap, CopyOnWriteArrayList).

Concept

Fail-Fast

Collections like ArrayList maintain an internal integer called modCount (modification count). Every time you add() or remove(), modCount increases. When you create an Iterator, it remembers the modCount. During iteration, if the Iterator notices that the collection’s modCount no longer matches its remembered count, it fails fast and throws an exception to prevent chaotic behavior.

Fail-Safe

Fail-safe iterators allow concurrent modification.
Classes like CopyOnWriteArrayList achieve this by making a completely new copy of the internal array every time a write operation occurs. The iterator continues reading from the old, unmodified copy of the array.

Examples

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

public class IteratorTypesExample {
    public static void main(String[] args) {
        
        // 1. FAIL-FAST EXAMPLE
        List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
        try {
            for (String s : list) {
                if (s.equals("A")) {
                    list.remove(s); // Modifying collection directly
                }
            }
        } catch (ConcurrentModificationException e) {
            System.out.println("Fail-Fast triggered!");
        }

        // 2. FAIL-SAFE EXAMPLE
        List<String> safeList = new CopyOnWriteArrayList<>(Arrays.asList("A", "B", "C"));
        for (String s : safeList) {
            if (s.equals("A")) {
                safeList.remove(s); // Totally safe!
            }
        }
        System.out.println("Fail-Safe finished. List is now: " + safeList);
    }
}

Interview Questions

Q: Can a Fail-Fast iterator throw ConcurrentModificationException in a single-threaded environment?
A: Yes. The exception has the word “Concurrent” in it, which often confuses developers into thinking it only happens in multi-threading. As shown in the example above, simply using a for-each loop and calling list.remove() in a single thread will trigger a ConcurrentModificationException.

Q: Why isn’t every collection Fail-Safe?
A: Because Fail-Safe mechanisms have high overhead. CopyOnWriteArrayList creates a brand new array and copies every element over for every single add or remove operation, which consumes massive amounts of memory and CPU if the list is large or frequently modified. Fail-fast is the default because it is highly performant.