Introduction
ConcurrentModificationException is thrown when a collection is structurally modified while being iterated, except through the iterator's own remove or add methods. This is a fail-fast behavior designed to detect bugs where code modifies a collection during traversal.
This is one of the most common collection-related errors in Java, especially when filtering or cleaning up elements during a loop.
Symptoms
- Application throws "java.util.ConcurrentModificationException" during foreach loop
- Exception occurs at the next iteration after removing an element
- Code works for some inputs but fails when the removal condition is triggered
Common Causes
- Using foreach loop and calling list.remove() inside the loop body
- Modifying a collection from another thread while iterating
- Using stream().forEach() and modifying the source collection inside the lambda
Step-by-Step Fix
- 1.Use Iterator.remove() for safe removal during iteration: The iterator's own remove method is safe.
- 2.```java
- 3.List<String> items = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));
Iterator<String> it = items.iterator(); while (it.hasNext()) { String item = it.next(); if (item.equals("b")) { it.remove(); // Safe - uses iterator's remove } } // Result: [a, c, d] ```
- 1.Use removeIf for predicate-based filtering: Clean one-liner for conditional removal.
- 2.```java
- 3.List<String> items = new ArrayList<>(Arrays.asList("a", "b", "c", "d"));
// Remove all items matching a condition items.removeIf(item -> item.equals("b")); // Result: [a, c, d] ```
- 1.Collect to a new list instead of modifying in place: Create a filtered copy.
- 2.```java
- 3.List<String> items = Arrays.asList("a", "b", "c", "d");
// Create a new list without the unwanted elements List<String> filtered = items.stream() .filter(item -> !item.equals("b")) .collect(Collectors.toList()); ```
- 1.Use concurrent collections for multi-threaded access: CopyOnWriteArrayList for thread-safe iteration.
- 2.```java
- 3.import java.util.concurrent.CopyOnWriteArrayList;
List<String> items = new CopyOnWriteArrayList<>(Arrays.asList("a", "b", "c", "d"));
// Safe to modify during iteration in multi-threaded context for (String item : items) { if (item.equals("b")) { items.remove(item); // Safe with CopyOnWriteArrayList } } ```
Prevention
- Never call list.remove() inside a foreach loop -- use Iterator.remove() or removeIf()
- Use removeIf() for simple predicate-based filtering
- Use CopyOnWriteArrayList or ConcurrentHashMap for concurrent read-write scenarios
- Prefer immutable collections and functional filtering over in-place modification