Fail-Fast Iterator in Java
Problem
ArrayList's iterator is fail-fast — it detects when the list has been structurally changed by anything other than itself, and throws ConcurrentModificationException rather than continuing with a corrupted view of the list.
Iterate a list with a for-each loop, modify the list directly from inside the loop, and observe the exception that results.
Java Program
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.List;
public class FailFastIteratorDemo {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);
numbers.add(5);
try {
for (int n : numbers) {
if (n == 2) {
numbers.remove(Integer.valueOf(2)); // structural change outside the iterator
}
}
} catch (ConcurrentModificationException e) {
System.out.println("Caught: ConcurrentModificationException");
}
}
}Output
Core Logic
Removing an element straight from the list — instead of through the iterator — changes the list's internal modification count mid-loop, and the for-each loop's hidden iterator detects that mismatch on its very next step.
- 1The for-each loop over
numbersis secretly backed by anIterator, even though noIteratorvariable is written explicitly. - 2When
n == 2,numbers.remove(Integer.valueOf(2))removes the element directly from the list itself, not through the iterator. - 3That removal is a structural change the iterator never authorized, so it records a mismatch internally.
- 4The very next call the loop makes into the iterator — checking for or fetching the next element — detects that mismatch and throws
ConcurrentModificationException, caught here to keep the output clean.
2 while three elements (3, 4, 5) still remain unvisited is what guarantees the exception fires — the iterator still has more work to do when it discovers the list changed underneath it.Key Point: This is a deliberate safety mechanism, not a bug — silently continuing to iterate over a list that changed size mid-loop could skip elements or revisit them, so ArrayList's iterator would rather fail loudly than fail silently.
Why: This file is really about a runtime safety guarantee rather than a performance characteristic — the loop only advances through as many elements as it takes to hit the exception, and no extra storage is used beyond the iterator's own position.