ConcurrentModificationException while iterating Ma

2019-01-28 06:58发布

I have the following code below

Map<String, Integer> buyingItemEnumerationMap = this.toBuyItemEnumeration;
for (Entry<String, Integer> item : buyingItemEnumerationMap.entrySet()) {
   if(RandomEngine.boolChance(50)){ //will delete?
    buyingItemEnumerationMap.remove(item.getKey());
   }
   if(buyingItemEnumerationMap.size() == 1){
    break;
   }
}

now I am working with an android game and the code above is running in multithreaded way. Now I am having an exception which is java.util.ConcurrentModificationException. I already researched on how I can solve the problem but seems not to work on me. What I am doing on the code above is to remove an entry randomly. How can I implement it there?

4条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-01-28 07:29

Yes you can't delete entries in a Map while traversing it by it's own property. different approch.

查看更多
放荡不羁爱自由
3楼-- · 2019-01-28 07:36

You cannot remove an element from a collection while iterating it unless you use an Iterator.

This is what's causing the exception.

buyingItemEnumerationMap.remove(item.getKey());

Use Iterator#remove() to remove an element while iterating over your collection like

Iterator<Map.Entry<String, Integer>> iterator = 
                           buyingItemEnumerationMap.entrySet().iterator();
while (iterator.hasNext()) {
   Map.Entry<String, Integer> item = iterator.next();
   if(RandomEngine.boolChance(50)){ //will delete?
      iterator.remove();
   }
   //..
}

EDIT : (in response to OP's comment)
Yes, the deletions done through Iterator#remove() over the Set returned by HashMap.entrySet() would reflect in the underlying Map as the Set is backed by it. Quoting the JavaDoc here:

Returns a Set view of the mappings contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa.

查看更多
我欲成王,谁敢阻挡
4楼-- · 2019-01-28 07:38

Use iterator in the forEach loop and use iterator.remove();

查看更多
Deceive 欺骗
5楼-- · 2019-01-28 07:53

Use Iterator.

Iterator<Map.Entry<String, Integer>> iter = this.toBuyItemEnumeration;
while (iter.hasNext()) {
    Map.Entry<String, Integer> entry = iter.next();
    if (some-condition){
        iter.remove();
    }
}

HOW IT WORKS ?

The javadoc for ConcurrentModificationException says:

If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.

The field int expectedModCount is initiated to be equal to the field protected transient int modCount = 0; (and this is valid for Collections and Maps), and modCount keeps track of the structural modifications over the object. If modCount at some point of the iteration gets unequal to expectedModCount, then a ConcurrentModificationException is thrown.

With using Iterator to make structural changes over the map/collection (like removing elements), we make sure that the removal operation will be executed properly, e.g. the modCount will be equal to the expectedModCount.

查看更多
登录 后发表回答