-->

issue with hashmap getting concurrent modification

2019-09-05 04:00发布

问题:

I am getting the below error while using map and performing some remove.How to avoid this ?

Caused by: java.util.ConcurrentModificationException
    at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)
    at java.util.HashMap$EntryIterator.next(HashMap.java:834)
    at java.util.HashMap$EntryIterator.next(HashMap.java:832)


   Map<FormField, Object> ItemMap = domainItem.getValues();         
   for (Map.Entry<FormField, Object> ValMap : ItemMap.entrySet()) {         
       List<Field> groupIdList = Mapper.getGroupId(groupFieldId);           
       for (Field field : groupIdList) {
           ItemMap.put(new FormField(field), domainItem.getDomainItemLinkId());
       }
       ItemMap.remove(ValMap.getKey());
   }

回答1:

Update:

Use Iterator and ConcurrentHashMap to avoid this scenario

Following won't throw exception

    Map<Integer, String> map = new ConcurrentHashMap<Integer, String>();
    map.put(1, "a");
    map.put(2, "b");
    map.put(3, "c");
    map.put(4, "d");
    for (Iterator<Integer> keys = map.keySet().iterator(); keys.hasNext();) {
        Integer key = keys.next();
        String val = map.get(key);
        map.remove(key);
    }

or use another map while iterating and at the end copy it to source

for example:

    Map<Integer, String> dummy = new HashMap<Integer, String>();
    map.put(1, "a");
    map.put(2, "b");
    map.put(3, "c");
    map.put(4, "d");
    dummy.putAll(map);
    for (Iterator<Integer> keys = dummy.keySet().iterator(); keys.hasNext();) {
        Integer key = keys.next();
        String val = map.get(key);
        map.remove(key);
    }
    System.out.println(map);


回答2:

A Map is sorted by the keys in the key-value pairs. When you add or remove elements from the Map while you are iterating through them, the program essentially loses track of "where" in the Map it is.

To get around this, try making a separate, temporary transfer Map. There is also a class called Iterator which might suit your needs.



回答3:

One way to avoid this issue is to iterate over a copy.

for (Map.Entry<FormField, Object> ValMap : 
     new HashMap<FormField, Object>(ItemMap).entrySet()) {


回答4:

can be done without a copy of the map, execute this example and take a look at the code:

public static void main(String[] args)
  {

    System.out.println("creating map ...");

    Map<String, String> dummyMap = new HashMap<>();
    while (dummyMap.size() < 10)
    { dummyMap.put(String.valueOf(new Random().nextInt()), String.valueOf(new Random().nextInt())); }


    System.out.println("start, map size: " + dummyMap.size() + ", keys=" + dummyMap.keySet());


    System.out.print("going to remove: ");
    for (Iterator<String> keys = dummyMap.keySet().iterator(); keys.hasNext(); )
    {
      final String key = keys.next();

      // delete map entries per random
      if(new Random().nextInt(3)>1)
      {
        System.out.print(key+" ");
        keys.remove();
      }
    }
    System.out.print("\n");

    System.out.println("done, map size: " + dummyMap.size() + ", keys=" + dummyMap.keySet());
  }

and take a look at this similar question.

HTH,