简体   繁体   中英

How to remove multiple mappings in hashmap without ConcurrentModificationException?

I have 2 hashmaps: HashMap<String, Word> hmSmall, hmBig . The mapping in each is many-to-one . Hence based on some criteria, I have to remove all the mappings corresponding to a particular value in both hashmaps. And for that, I am following this answer.

The problem is that I still get ConcurrentModificationException while iterating over the hashmap.

Here is the code:

for (Iterator<Word> it = hmSmall.values().iterator(); it.hasNext(); i++) {
            Word value = it.next();//java.util.ConcurrentModificationException here
            String key = value.getKey();
            if (hmBig.containsKey(key)) {
                // if big contains less then remove from big
                // else it.remove

                if (hmBig.get(key).getTotalOccurances() < value
                        .getTotalOccurances()) {

                    hmBig.values().removeAll(
                            Collections.singleton(hmBig.get(key)));

                } else {

                    // it.remove(); not using this based on https://stackoverflow.com/a/30214164/848377
                    hmSmall.values().removeAll(Collections.singleton(value));

                }

            }
        }

Is there simple way out?

Iterator.remove()必须通过Iterator.remove()删除,以避免ConcurrentModificationException

Your Problem is, that, while you iterate through your HashMap with the Iterator Class, you are changing the size of the HashMap by removing elements...

You can store the objects to be removed in a separate set and then remove all after the loop.

Compare the example from this stackoverflow post :

Map<String, String> map = new HashMap<>();
map.put("a", "");
map.put("b", "");
map.put("c", "");

Set<String> set = new HashSet<> ();
set.add("a");
set.add("b");

map.keySet().removeAll(set);

System.out.println(map); //only contains "c"

Just put the removeAll call outside the loop:

   public static void main(String[] args) {
    // The test map
    final Map<String, String> map = new HashMap<String, String>();
    map.put("Key1", "Value");
    map.put("Key2", "Value");
    map.put("Key3", "Value");

    .


    // Print the map to confirm it worked.
    for(final String key : map.keySet()) {
        map.values().removeAll(Collections.singleton("Value"));
       System.out.println(key + " = " + map.get(key));
    }
}

the previous will cause exception ( ConcurrentModificationException ) try this:

 public static void main(String[] args) {
    // The test map
    final Map<String, String> map = new HashMap<String, String>();
    map.put("Key1", "Value");
    map.put("Key2", "Value");
    map.put("Key3", "Value");


    map.values().removeAll(Collections.singleton("Value"));


    for(final String key : map.keySet()) {
       System.out.println(key + " = " + map.get(key));
    }
}

Now it works fine

As @Ejp suggested , Iterator#remove() is the optimal solution to get rid of ConcurrentModificationException .

A similar kind of post here Iterating through a Collection, avoiding ConcurrentModificationException when removing in loop .

Also with java8 , you can very well use removeIf() method . Have a look at Iterating through a Collection, avoiding ConcurrentModificationException when removing in loop

So the key point here is not to change the size of the hashmap while iterating. Thus instead of deleting the entry within the loop, I added the key in an arraylist. And when the loop got over, I traversed through that arraylist and deleted the entries of the hashmap corresponding to the key in the arraylist.

Here is the code:

ArrayList<String> alsmallhm=new ArrayList<String>();
        for (Iterator<Word> it = hmSmall.values().iterator(); it.hasNext(); i++) {
            Word value = it.next();//java.util.ConcurrentModificationException here
            String key = value.getKey();
            if (hmBig.containsKey(key)) {
                // if big contains less then remove from big
                // else it.remove

                if (hmBig.get(key).getTotalOccurances() < value
                        .getTotalOccurances()) {

                    hmBig.values().removeAll(
                            Collections.singleton(hmBig.get(key)));

                } else {

                    // it.remove();
                    alsmallhm.add(key);
                    /*hmSmall.values().removeAll(Collections.singleton(value));*/

                }

            }
        }

        for(String s:alsmallhm){
            hmSmall.values().removeAll(Collections.singleton(hmSmall.get(s)));
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM