ConcurrentModificationException in Java
Fast recall
Quick revision
Core answer
ConcurrentModificationException when they detect an unsupported structural change during iteration. It can happen in one thread and is only a best-effort bug detector, not a concurrency guarantee. Use an iterator's supported removal, removeIf, a new result collection, or a concurrent collection with documented snapshot or weakly consistent iteration.Understanding of collection iteration internals and fail-fast behavior — a very common practical mistake
Trying to remove elements directly from a List inside a for-each loop, which immediately throws this exception
Explain all three safe alternatives clearly and demonstrate why the for-each loop fails (iterator invalidation)
Interview-ready guide
Interview answer
ConcurrentModificationException is commonly thrown when a fail-fast iterator detects that its collection was structurally changed through an unsupported path. A for-each loop over ArrayList uses an iterator, so direct list removal can trigger it even in one thread.
The check is best effort and implementation-specific; it must not be used as a concurrency guarantee. I use an iterator's remove only when supported, removeIf for simple filtering, or create another result. When threads share the structure, I choose a suitable concurrent collection and its documented iteration model rather than trying merely to avoid the exception.
ConcurrentModificationException in Java
Direct Answer
Many standard fail-fast iterators may throw ConcurrentModificationException when they detect an unsupported structural change during iteration. It can happen in one thread and is only a best-effort bug detector, not a concurrency guarantee. Use an iterator's supported removal, removeIf, a new result collection, or a concurrent collection with documented snapshot or weakly consistent iteration.
Code Example
public class OrderProcessor {
public void cleanupOrders(List<Order> orders) {
// WRONG: modifying list during for-each loop
// for (var order : orders) {
// if (order.isExpired()) {
// orders.remove(order); // throws ConcurrentModificationException
// }
// }
// SOLUTION 1: use Iterator.remove (single element removal)
var iterator = orders.iterator();
while (iterator.hasNext()) {
var order = iterator.next();
if (order.isExpired()) {
iterator.remove(); // safe: removes through iterator
}
}
}
public void removeInvalidOrders(List<Order> orders) {
// SOLUTION 2: removeIf with predicate (Java 8+)
orders.removeIf(order -> order.getTotal() < 0);
}
public void cancelPendingOrders(List<Order> orders) {
// SOLUTION 3: collect items to remove, then remove in second pass
var toRemove = orders.stream()
.filter(order -> order.getStatus().equals("PENDING"))
.toList();
orders.removeAll(toRemove); // bulk removal after iteration
}
}
Common Mistakes & Pitfalls
- Calling list.remove inside for-each loop: This is the classic mistake. Freshers write for var order colon orders then call orders.remove(order) inside the loop. The for-each loop uses an iterator behind the scenes, and calling remove on the list directly breaks the iterator's modification tracking. The exception is thrown on the next iteration when the iterator detects the mismatch.
- Using index-based loop with list.remove: Writing a for loop from zero to size and calling list.remove(i) seems safe but has a subtle bug. When you remove an element, all subsequent elements shift down one index, but your loop counter keeps incrementing. You skip the element that moved into the removed element's position. While this doesn't throw ConcurrentModificationException, it produces wrong results.
- Modifying during stream operations: Trying to modify the source collection inside a stream's forEach or filter throws ConcurrentModificationException. Streams are not designed for modifying their source — use removeIf or collect results into a new collection instead.
Check your understanding
Answer these without looking back at the article.
- What is the modCount field in ArrayList?
- How does CopyOnWriteArrayList avoid ConcurrentModificationException?
- Is ConcurrentModificationException always from concurrent thread access?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.