Why Removing Elements from a HashMap During a For‑Each Loop Causes ConcurrentModificationException and How to Fix It
Iterating a HashMap with a for‑each loop while calling its remove method triggers a ConcurrentModificationException because the loop uses an internal iterator that becomes inconsistent with the map’s modCount, and the article explains the cause, shows decompiled code, and provides correct removal approaches using the iterator or removeIf.
When a HashMap is traversed with a for‑each loop over entrySet() and the map’s remove method is invoked at the same time, a ConcurrentModificationException is thrown even in a single‑threaded context.
Reproduction
public static void main(String[] args) {
Map
map = new HashMap<>();
map.put("a", 1);
map.put("b", "b");
for (Map.Entry
entry : map.entrySet()) {
if (entry.getKey().equals("a")){
map.remove("a");
}
}
}Running the above code on Java 17 produces the following stack trace:
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1597)
at java.base/java.util.HashMap$EntryIterator.next(HashMap.java:1630)
at java.base/java.util.HashMap$EntryIterator.next(HashMap.java:1628)
at com.example.springcloudtest.spring.postprocessor.Test.main(Test.java:20)Root cause
The for‑each loop internally uses the iterator java.util.HashMap.EntryIterator . The iterator checks the map’s modCount against its own expectedModCount . Calling HashMap.remove(Object) updates the map’s modCount but does not update the iterator’s expectedModCount , causing the mismatch and the exception.
Decompiled version of the loop (without syntactic sugar) shows the explicit iterator usage:
public class Test {
public static void main(String[] args) {
Map
map = new HashMap();
map.put("a", 1);
map.put("b", "b");
Iterator var2 = map.entrySet().iterator();
while(var2.hasNext()) {
Entry
entry = (Entry)var2.next();
if (((String)entry.getKey()).equals("a")) {
map.remove("a");
}
}
}
}Therefore, when iterating with an iterator, removal must be performed through the iterator itself, not through the collection’s remove method.
Corrected examples
1. Use the iterator’s remove() method:
public static void main(String[] args) {
Map
map = new HashMap<>();
map.put("a", 1);
map.put("b", "b");
System.out.println(map);
Iterator
> iterator = map.entrySet().iterator();
while (iterator.hasNext()){
Map.Entry
next = iterator.next();
if (next.getKey().equals("a")){
iterator.remove();
}
}
System.out.println("删除后:" + map);
}2. Use Collection.removeIf directly on the entry set:
public static void main(String[] args) {
Map
map = new HashMap<>();
map.put("a", 1);
map.put("b", "b");
map.entrySet().removeIf(entry -> entry.getKey().equals("a"));
System.out.println(map);
}Summary
The for‑each loop in Java is syntactic sugar for an iterator; removing elements via the map’s own remove while iterating breaks the iterator’s consistency check and triggers ConcurrentModificationException . Use the iterator’s remove() method or removeIf to safely delete entries during iteration.
Cognitive Technology Team
Cognitive Technology Team regularly delivers the latest IT news, original content, programming tutorials and experience sharing, with daily perks awaiting you.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.