ConcurrentModificationException
Fast recall
Quick revision
Core answer
ConcurrentModificationException after an unsupported structural change during iteration. This is a best-effort bug detector, not a concurrency guarantee, and implementation details such as modCount are not part of the Collection contract. Use the iterator's supported remove(), removeIf(), a separate result collection, or a concurrent collection whose iteration semantics fit the task.Understanding of Java's fail-fast iterator mechanism and knowledge of the modCount field that tracks structural modifications to collections
Calling list.remove(element) directly inside a for-each loop instead of using iterator.remove(), when that iterator supports removal
Explain the modCount mechanism that underlies fail-fast behavior and demonstrate knowledge of CopyOnWriteArrayList and its snapshot-iteration trade-off for concurrent scenarios
Interview-ready guide
Interview answer
ConcurrentModificationException is commonly thrown when a fail-fast iterator notices that its collection was structurally changed outside the iterator. For example, a for-each loop over an ArrayList uses an iterator, so calling list.remove() inside the loop can invalidate it.
I treat fail-fast behavior as a bug detector, not as a thread-safety mechanism. The JDK documents it as best effort, and details such as modCount belong to particular implementations. For single-thread filtering I use the iterator's remove(), removeIf(), or produce another collection. If threads really share the collection, I choose a concurrent type and understand its iterator semantics—for example, snapshot iteration in CopyOnWriteArrayList—rather than merely trying to suppress the exception.
ConcurrentModificationException
Direct Answer
Many standard collection iterators are fail-fast and may throw ConcurrentModificationException after an unsupported structural change during iteration. This is a best-effort bug detector, not a concurrency guarantee, and implementation details such as modCount are not part of the Collection contract. Use the iterator's supported remove(), removeIf(), a separate result collection, or a concurrent collection whose iteration semantics fit the task.
Code Example
The unsupported form is best described as may throw, because fail-fast detection is best effort.
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
public class OrderFilter {
static void unsupportedChange(List<String> orders) {
for (String order : orders) {
if (order.equals("cancelled")) {
orders.remove(order); // may invalidate this iterator and cause CME
}
}
}
static void removeWithIterator(List<String> orders) {
Iterator<String> it = orders.iterator();
while (it.hasNext()) {
if (it.next().equals("cancelled")) {
it.remove(); // supported by ArrayList's iterator
}
}
}
static void removeWithPredicate(List<String> orders) {
orders.removeIf("cancelled"::equals);
}
static void snapshotExample(CopyOnWriteArrayList<String> orders) {
for (String order : orders) {
orders.remove(order); // loop still sees its earlier snapshot
}
}
}
CopyOnWriteArrayList is useful only for read-heavy cases: every successful write copies its backing array.
Common Mistakes & Pitfalls
- Treating CME as a thread-safety guarantee: fail-fast checks are best effort and must not be used to prove that access is safe.
- Catching and ignoring it: the iteration or update may be incomplete; fix the unsupported modification instead.
- Assuming every collection has
modCount: that is an implementation detail used by several JDK collections, not an interface rule. - Calling every alternative fail-safe: use documented terms such as snapshot iteration for
CopyOnWriteArrayListand weakly consistent iteration forConcurrentHashMap. - Using copy-on-write for frequent updates: each write copies the backing array.
Check your understanding
Answer these without looking back at the article.
- What is the difference between fail-fast and fail-safe iterators?
- How does removeIf() work internally?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.