Java HashMap concurrent modification error
Interesting question here. Why does the first version of this throw throws a concurrent modification error while the second doesn't. If this happens?
Map<String,Integer> map = new HashMap<>();
... // Populate the map
for(String key : map.keySet()){
if(map.get(key) < 50){
map.remove(key);
}
}
Map<String,Integer> map = new HashMap<>();
... // Populate the map
for(String key : new ArrayList<String>(map.keySet())){
if(map.get(key) < 50){
map.remove(key);
}
}
source to share
The first example throws an exception because you are modifying the map while iterating over it. This is expected.
In the second example, you create an ArrayList containing all the lines in the map. Here you are iterating over the newly created ArrayList, so your second example does not throw the example because you are iterating over the ArrayList, not over the map
source to share
it
for(String key : map.keySet()){
if(map.get(key) < 50){
map.remove(key);
}
}
will always throw ConcurrentModificationException
because you are removing elements during iteration. You will need Iterator
one that has an operation remove
:
for(Iterator<Map.Entry<String, Integer>> it = map.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<String, Integer> entry = it.next();
if(entry.getValue() < 50) {
it.remove();
}
}
There is also ConcurrentHashMap
one that supports concurrent operations and only blocks buckets if you need to.
source to share
In the first case, you get a concurrentModificationException, because the number of changes associated with the iteration is in terms of internal implementation. If the number of changes changes during iteration, a concurrentModificaitonException is thrown.
The solution is to use iterator.remove () instead of removing the element directly from the map.
In the second case, you are repeating not a map, but a different collection, removing the element from the map. In this case, the revision counter never changes during iteration because you are iterating over a different collection.
Also, in a multi-threaded environment, always use sync on the collection that represents the shared mutable state in the class before iterating it, otherwise you might get a concurrentModificationException.
In a multi-threaded environment, your second solution will not be correct because you have not synchronized the statement in which you are passing the source map set to the new collection. Thus, it is possible to get a concurrentModificationException. Use ConcurrentHashMap in a multithreaded environment, knowing that not every operation or set of operations in ConcurrentHashMap is insecure by default.
source to share