💥 Why does ConcurrentModificationException happen?
It occurs when:
- You’re iterating over a collection (using an
Iteratororfor-eachloop) - And the collection is structurally modified outside the iterator during iteration
✅ How to Avoid It — 5 Safe Strategies
✅ 1. Use the Iterator’s remove() method
Only use the iterator itself to remove elements — never the collection.
List<String> list = new ArrayList<>(List.of("A", "B", "C"));
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if (it.next().equals("B")) {
it.remove(); // ✅ Safe — handled by iterator
}
}
❌ Don’t do this:
for (String s : list) {
if (s.equals("B")) {
list.remove(s); // ❌ ConcurrentModificationException
}
}
✅ 2. Use a ListIterator if you need to add(), set(), or remove()
List<String> list = new ArrayList<>(List.of("A", "B", "C"));
ListIterator<String> lit = list.listIterator();
while (lit.hasNext()) {
String val = lit.next();
if (val.equals("B")) {
lit.set("Beta"); // ✅ Replaces "B"
lit.add("Bravo"); // ✅ Adds after "Beta"
}
}
✅ 3. Iterate over a copy of the collection
If you need to modify the collection while iterating — don’t iterate over the original.
List<String> list = new ArrayList<>(List.of("A", "B", "C"));
for (String s : new ArrayList<>(list)) {
if (s.equals("B")) {
list.remove(s); // ✅ Safe, because we're iterating over a copy
}
}
Works well for read-modify scenarios where performance isn’t critical.
✅ 4. Use Concurrent Collections (fail-safe)
In multithreaded environments, use classes from java.util.concurrent, such as:
CopyOnWriteArrayListConcurrentHashMapConcurrentSkipListSet
These do not throw ConcurrentModificationException, even when modified during iteration.
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>(List.of("A", "B", "C"));
for (String s : list) {
if (s.equals("B")) {
list.remove(s); // ✅ Safe in CopyOnWriteArrayList
}
}
⚠️ Trade-off: expensive for frequent writes (since copies are made on every modification).
✅ 5. Use streams or filters instead of manual removal
List<String> list = new ArrayList<>(List.of("A", "B", "C"));
list = list.stream()
.filter(s -> !s.equals("B")) // keep everything except "B"
.collect(Collectors.toList()); // ✅ Safe
Cleaner, functional style — often better for batch filtering.
🧠 Summary Table
| Strategy | Safe? | Notes |
|---|---|---|
iterator.remove() | ✅ | Standard safe method during iteration |
| Modifying collection directly | ❌ | Causes exception during iteration |
| Iterating over a copy | ✅ | Safe and easy, may use more memory |
Using ListIterator | ✅ | Allows bidirectional traversal and modification |
| Using concurrent collections | ✅ | Thread-safe, no exception, but slower on writes |
| Using stream/filter | ✅ | Functional, clean, not in-place |