I came across ConcurrentModificationException while editing LinkedHashMap which internally maintains order of the tuple. Below is my code to edit the map. It looks fine to me and no compilation errors too. But, during runtime I faced ConcurrentModificationException even though it’s not multi-thread environment.
Map<Key, Value> map = getMap(); // map generating is hidden
for (Key key : map.keySet()) {
if (isToRemove(key)) {
map.remove(key);
} else {
map.put(key, getNewValue());
}
}
Exception in thread
"main"
java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:
372
)
at java.util.AbstractList$Itr.next(AbstractList.java:
343
)
From this stack trace, its clear that the exception is coming when we call iterator next() function. If you are wondering how Iterator checks for the modification, its implementation is present in AbstractList class where an int variable modCount is defined that provides the number of times list size has been changed. This value is used in every next() call to check for any modifications in a function checkForComodification().
To fix the issue, after exploring I came to know following facts. You should never modify Map during traversal as modifying key will break Map collection, rather you should use iterator to modify the current Map.Entry object which will not complaint this error. You can use the iterator remove() function to remove the object from underlying collection object. But in this case you can remove the same object and not any other object from the list.
Modified above code to fix the issue is:-
Map<Key, Value> map = getMap();
for (var entryIterator = map.entrySet().iterator(); entryIterator.hasNext(); ) {
var entry = entryIterator.next();
if (isToRemove(entry.getKey())) {
entryIterator.remove();
} else {
entry.setValue(getNewValue());
}
}
Better explanation, you can refer to Java SDK Docs.