How to Fix ConcurrentModificationException in Java (Beginner Guide)
Fix the ConcurrentModificationException in Java: why it happens when you modify a collection while looping, and four correct fixes including removeIf and iterator.remove.
The ConcurrentModificationException is one of those errors with a scary name that actually has a simple cause: you changed a collection while looping over it. It surprises nearly every beginner (and its name misleadingly suggests threads). This guide explains exactly why it happens and shows you the correct ways to modify a collection during iteration.
What triggers it
ConcurrentModificationException is thrown when you add or remove elements from a collection while iterating over it with a for-each loop or iterator. Despite the name, it usually has nothing to do with multiple threads.
The classic mistake — trying to remove items during a for-each loop:
List<String> list = new ArrayList<>(List.of("a", "b", "c")); for (String s : list) { if (s.equals("b")) { list.remove(s); // 💥 ConcurrentModificationException! } }
Why does this happen?
A for-each loop uses an iterator behind the scenes. The iterator keeps track of the collection's "modification count." When you call list.remove() directly, that count changes, but the iterator doesn't know about it. On the next step, the iterator notices the mismatch — "someone modified this behind my back!" — and fails fast by throwing the exception, rather than risk skipping elements or producing corrupt results. It's actually a safety feature.
The correct ways to fix it
1. Use the iterator's own remove() method
The iterator's remove() safely removes the current element and keeps the count in sync:
Iterator<String> it = list.iterator(); while (it.hasNext()) { String s = it.next(); if (s.equals("b")) { it.remove(); // ✓ safe — the iterator does the removing } }
2. Use removeIf() — the cleanest option
Modern Java gives you a one-liner that handles removal safely and reads beautifully:
list.removeIf(s -> s.equals("b")); // ✓ safe and concise
For most "remove elements matching a condition" cases, removeIf is the best answer — prefer it.
3. Collect, then remove after the loop
List<String> toRemove = new ArrayList<>(); for (String s : list) { if (s.equals("b")) toRemove.add(s); } list.removeAll(toRemove); // ✓ modify AFTER iterating
4. Iterate over a copy
// loop over a copy, modify the original for (String s : new ArrayList<>(list)) { if (s.equals("b")) list.remove(s); // ✓ safe — iterating a different list }
removeIf() first — it's the cleanest and safest for condition-based removal. Use the explicit iterator.remove() when your logic is more complex. Avoid modifying a collection inside a plain for-each loop entirely; that's the root of the problem. (Related: this is the fail-fast iterator behaviour interviewers ask about.)
This one genuinely confused me the first time because of its name — I went hunting for threading bugs that didn't exist, when the real issue was simply removing from a list mid-loop. Once I understood it's a fail-fast safety feature (the iterator refusing to continue after a sneaky modification), it stopped being scary and started making sense. My practical rule now: never mutate a collection inside a for-each loop; use removeIf for the common case and the explicit iterator when I need finer control. Learn those two, and this exception simply stops appearing in your code.