java.util.ConcurrentModificationException
java.util.ConcurrentModificationException
DodaTech
3 min read
ConcurrentModificationException fires when you modify a collection while iterating it. Java’s fail-fast iterators detect this and stop to prevent data corruption.
What It Means
You have a loop (typically a for-each loop) that’s iterating over a List, Set, or Map, and somewhere inside the loop body you add or remove elements from that same collection. The iterator detects the modification and throws immediately to prevent undefined behavior.
Why It Happens
- You call
list.remove()inside a for-each loop. - You call
list.add()while iterating with an iterator. - One thread modifies a collection while another thread iterates over it.
- You use
map.put()ormap.remove()inside a loop overmap.keySet(). - You’re using a sublist and modify the parent list.
How to Fix It
1. Use iterator.remove() instead of collection.remove()
List<String> names = new ArrayList<>(List.of("Alice", "Bob", "Charlie"));
// BUG: ConcurrentModificationException
for (String name : names) {
if (name.equals("Bob")) {
names.remove(name); // throws
}
}
// FIX: use iterator directly
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String name = it.next();
if (name.equals("Bob")) {
it.remove(); // safe — iterator's own method
}
}2. Collect removals and apply after the loop
List<String> names = new ArrayList<>(List.of("Alice", "Bob", "Charlie"));
List<String> toRemove = new ArrayList<>();
for (String name : names) {
if (name.equals("Bob")) {
toRemove.add(name);
}
}
names.removeAll(toRemove); // modify after iteration3. Use removeIf (Java 8+)
names.removeIf(name -> name.equals("Bob"));This single line does the iteration and removal safely.
4. Use CopyOnWriteArrayList for concurrent access
import java.util.concurrent.CopyOnWriteArrayList;
List<String> safeList = new CopyOnWriteArrayList<>(List.of("Alice", "Bob"));
// Safe to modify during iteration
for (String name : safeList) {
if (name.equals("Bob")) {
safeList.remove(name);
}
}CopyOnWriteArrayList creates a fresh copy on every mutation, so iteration sees a consistent snapshot.
5. For Maps, iterate over entrySet and use iterator
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 90);
scores.put("Bob", 85);
// FIX: use iterator on entrySet
Iterator<Map.Entry<String, Integer>> entryIt = scores.entrySet().iterator();
while (entryIt.hasNext()) {
Map.Entry<String, Integer> entry = entryIt.next();
if (entry.getValue() < 60) {
entryIt.remove(); // safe
}
} Previous
Invalid conversion from throwing function
Next
PHP Fatal error: Allowed memory size of ... bytes exhausted
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro