What is the difference between fail-fast and fail-safe iterators in Java?

A fail-fast iterator throws ConcurrentModificationException as soon as it detects that the collection was structurally changed (an element added or removed) by anything other than the iterator itself. A fail-safe iterator works on a copy or a weakly consistent view, so it never throws that exception, but it may not show the latest changes.

Key Points: • Fail-fast: the iterators of ArrayList, HashMap, HashSet and most java.util collections. They track a modification count (modCount) and check it on every next(). • Fail-safe: the iterators of CopyOnWriteArrayList and ConcurrentHashMap (java.util.concurrent). • CopyOnWriteArrayList iterates over a snapshot taken when the iterator was created. ConcurrentHashMap's iterator is weakly consistent: it may or may not reflect changes made during iteration. • Fail-fast behaviour is "best effort": it helps you find bugs, but you should not rely on it for correctness. • Removing through the iterator itself (iterator.remove()) is allowed and does not trigger the exception.

Code Example:

import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class FailFastVsFailSafe {

    public static void main(String[] args) {
        List<String> failFast = new ArrayList<>(List.of("A", "B", "C"));
        try {
            for (String s : failFast) {
                if (s.equals("A")) failFast.add("D");     // structural change
            }
        } catch (ConcurrentModificationException e) {
            System.out.println("ArrayList: ConcurrentModificationException");
        }

        List<String> failSafe = new CopyOnWriteArrayList<>(List.of("A", "B", "C"));
        for (String s : failSafe) {
            if (s.equals("A")) failSafe.add("D");         // iterator uses a snapshot
            System.out.print(s + " ");
        }
        System.out.println();
        System.out.println("After loop: " + failSafe);
    }
}

Output:

ArrayList: ConcurrentModificationException A B C After loop: [A, B, C, D]

Good to Know: A common follow-up is "How do you remove elements while iterating?" Use iterator.remove(), or list.removeIf(condition) from Java 8, which is the cleanest option. Never call list.remove() inside a for-each loop.

Interview Tip: A concise interview answer is:

"A fail-fast iterator, like those of ArrayList and HashMap, throws ConcurrentModificationException when the collection is structurally modified during iteration, using a modification counter. A fail-safe iterator, like those of CopyOnWriteArrayList and ConcurrentHashMap, works on a snapshot or a weakly consistent view, so it doesn't throw, but it may not see the latest changes."

Previous question: What is the best way to iterate over a HashMap in Java?

Next question: How do you avoid ConcurrentModificationException when removing elements from a list?

More Java Collections interview questions

All Java Collections questions