Complile error ConcurrentModificationException, trying to use method for removing the same names

StackOverflow https://stackoverflow.com/questions/21952648

  •  15-10-2022
  •  | 
  •  

Pregunta

Im trying to make my removeItemFromMapByValue method work together with removeItemFromMapByValue, but when i start to compile my code i get that ConcurrentModificationException. removeItemFromMapByValue have to remove the same names in values.

    public class Solution
        {
            public static HashMap<String, String> createMap()
            {
                HashMap<String, String> map = new HashMap<String, String>();
                map.put("Stallone", "Silvest");
                map.put("Morikone", "Enio");
                map.put("Vivaldi","Antonio");
                map.put("Belucci", "Monica");
                map.put("Gudini", "Harry");
                map.put("Verdo", "Dhuzeppe");
                map.put("Maracci", "Bruno");
                map.put("Carleone", "Vito");
                map.put("Bracco", "Luka");
                map.put("Stradivari", "Antonio");
                return map;
            }
            public static void removeTheFirstNameDuplicates(HashMap<String, String> map)
            {
                for (Map.Entry<String, String> pair : map.entrySet()){
                    String name = pair.getValue();
                    removeItemFromMapByValue(map, name);
                }
            }
            public static void removeItemFromMapByValue(HashMap<String, String> map, String value)
            {
                HashMap<String, String> copy = new HashMap<String, String>(map);
                for (Map.Entry<String, String> pair: copy.entrySet())
                {
                    if (pair.getValue().equals(value))
                        map.remove(pair.getKey());
                }
            }
            public static void main(String[] args)
            {
                HashMap<String, String> map = createMap();
                removeTheFirstNameDuplicates(map);
                System.out.println(map);
            }
        }

Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.HashMap$HashIterator.nextEntry(HashMap.java:926)
    at java.util.HashMap$EntryIterator.next(HashMap.java:966)
    at java.util.HashMap$EntryIterator.next(HashMap.java:964)
    at com.javarush.test.level08.lesson08.task05.Solution.removeTheFirstNameDuplicates(Solution.java:32)
    at com.javarush.test.level08.lesson08.task05.Solution.main(Solution.java:52)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

Process finished with exit code 1
¿Fue útil?

Solución

The simple solution is to fix the first method, as this will avoid the error and behave correctly.

// remove any duplicated values, leaving one entry.
public static void removeTheFirstNameDuplicates(HashMap<String, String> map) {
     Map<K,V> map2 = invert(invert(map));
     map.clear();
     map.putAll(map2);
}

public static <K, V> Map<V, K> invert(Map<K, V> map) {
     Map<V, K> map2 = new HashMap<>();
     for(Map.Entry<K< V> entry: map.entrySet())
         map2.put(entry.getValue(), entry.getKey());
     return map2;
}

Your compiler will not produce a ConcurrentModifcationException. You should look at the line in in the stack track to see where you are modifying the collection while iterating over it e.g.

for (Map.Entry<String, String> pair: copy.entrySet())
{
    if (pair.getValue().equals(value))
        map.remove(pair.getKey());
}

In this case you are removing an entry while iterating. A simple solution is to use the Iterator directly. Usually you IDE can do this refactoring.

for (Iterator<String> iter = copy.values().iterator(); iter.hasNext();) {
    if (iter.next().equals(value))
        iter.remove();
}

The problem with this solution is this is called from a nested and it will remove ALL matching entries as it does in your code. i.e. it will remove all the entries.

Otros consejos

Here:

        for (Map.Entry<String, String> pair : map.entrySet()){
            String name = pair.getValue();
            removeItemFromMapByValue(map, name); //you are about to delete a map item here!
        }

You are modifying the Set that you are currently looping through ==> ConcurrentModificationException

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top