问题
I want to write code like this -
for (Map.Entry<Long, Integer> e : map.entrySet()){
map.remove(k);
map.put(x, value);
}
but I got java.util.ConcurrentModificationException
I tried to use Iterator also but I got the same Exception
回答1:
Explanation why it caused ConcurrentModificationException
map.remove(k);
map.put(x, value);
for-each loop also internally create a iterator of the entrySet of map. While iterating over map you have modified the structure of the map by putting the value again to the map (map.put(x,value)) which cause this ConcurrentModificationException.
It is even well explained in documentation -
The iterators returned by all of this class's "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
How to solve this -
you must change the change the structure of this map while iterating, you can insert this values later, like keep a temporary map and add this to the main map once iteration is finished his job.
Map<Long, Integer> tempMap = new HashMap<>();
for (Map.Entry<Long, Integer> e : map.entrySet()){
map.remove(k);
tempMap.put(x, value);
}
map.putAll(tempMap);
回答2:
Iterate over a copy and you can add/remove just fine:
for (Map.Entry<Long, Integer> e : new LinkedHashMap<Long, Integer>(map).entrySet()){
map.remove(k);
map.put(x, value);
}
It's not even any more lines of code, because the copy ims made in-line via the copy constructor. LinkedHashMap was chosen to preserve iteration order (if that matters).
回答3:
A sample code snippet for removing an element from the map is given below.
for(Iterator<Map.Entry<Long, Integer>> it = map.entrySet().iterator();it.next();)
{
Map.Entry<String, String> entry = it.next();
if(//some logic)
it.remove();
}
If your code involves a lot of addition and removal , you might just want to use ConcurrentHashMap.ConcurrentHashMap
回答4:
You will have to create a copy of your map using copy constructor. Now iterate on 1 and modify second map. I am assuming that you will not need to iterate newly added value as it wont make much sense.
You can achieve your task by creating a copy is because the keys will remain same in both.
EDIT:
I dont think its a good idea to iterate the newly added element to a Hashmap. If you check the api's provided by Iterator then you will find only remove method, there is no add method in it. There is a reason behind this and you can check javadoc for this. Now coming to the point, on how to iterate newly added element.
- Create a copy of your
HashMap. So you will iterate one and modify the the otherMap. - As the requirement is to both add and remove elements in
Map, i would like to useListIteratorfor this [this is different from normalIterator]. - I will get the
keysetof Map1 and convert it to a list usingArrayList(Collection<? extends E> c). - Now i will get
ListIteratorfromListcreated in step 3, and add, remove elements inListIteratoras well as in Map2 [Remeber you need to add , remove both inListIteratorand Map2].
回答5:
Because you can't do that.
An easy solution is to use another temporary map where you put the values you want and finally switch pointers with the original one (i.e Map = newMap )
来源:https://stackoverflow.com/questions/16637026/how-to-remove-and-add-elements-to-treemap-while-iterating