java.util.ConcurrentModificationException when removing elements from a hashmap

24,451

Solution 1

Your for-loop gets the map.entrySet and uses the iterator on it to work through the map entries (this version of the for-loop requires an Iterable, it gets the iterator from the Iterable). When you are using an iterator on a map, but remove things from the map without using that iterator, you get the ConcurrentModificationException. That is the map telling the iterator that it's out of date.

You can write a for loop using the iterator explicitly, like this:

for (Iterator<Map.Entry<String, Integer> it = map.entrySet().iterator();
it.hasNext();) {

and use the iterator's remove method when you need to delete an entry.

Solution 2

You are calling remove while you're iterating over the Map. This line, the enhanced for loop, runs an Iterator implicitly:

for(Map.Entry<String,Integer> entry : map.entrySet() )

When an Iterator detects that its collection is modified, it throws a ConcurrentModificationException. However, you can call remove() on the Iterator itself without that exception being thrown. Use an Iterator explicitly:

Iterator<Map.Entry<String, Integer>> itr = map.entrySet().iterator();
while(itr.hasNext())
{
   Map.Entry<String, Integer> entry = itr.next();
   if(entry.getValue().intValue() == 2)
   {
      System.out.println("Key : "+entry.getKey()+" Removed.");
      itr.remove();  // Call Iterator's remove method.
   }
}

Solution 3

You cannot remove an element from a map which you are currently iterating over. You could define an iterator, or you could make a few simple modifications to your code within the block for case 3.

case 3:
    System.out.print("Enter Value to remove : ");
    value = input.nextInt();
    if(map.containsValue(new Integer(value)))
    {
        Map.Entry<String,Integer> foo = null;
        for(Map.Entry<String,Integer> entry : map.entrySet() )
            if(entry.getValue().intValue() == value)
                foo = entry;

        System.out.println("Key : "+foo.getKey()+" Removed.");
        map.remove(foo.getKey());
    }
    break;

Solution 4

Just Use Iterator class to remove the Iterating Element as

for (Iterator<Map.Entry<String, Integer> it = map.entrySet().iterator();
while(it.hasNext()) {
  Map.Entry<String, Integer> e= itr.next();
  key = e.getKey();
  Value = e.getValue();

  //Your Other Code Here

   it.remove();                    //It removes the current Itertaion from Map


}
Share:
24,451
cyberpirate92
Author by

cyberpirate92

Other than coding, I also enjoy playing chess, reading books and occasionally blogging about stuff. Do Checkout my blog https://medium.com/@ravi_theja :)

Updated on July 09, 2022

Comments

  • cyberpirate92
    cyberpirate92 almost 2 years

    I am learning about HashMap class and wrote this simple program. this code works good for adding elements to the hashmap and while removing elements from the hashmap , I am encountering java.util.ConcurrentModificationException for example here is a copy of my terminal,

    [ravi@doom test]$ java TestHashMap 
    .....MENU.....
    1. Add
    2. remove key
    3. remove value
    4. display
    7. Exit
    Your choice :1
    
     Key : A
    
     Value : 1
    Key/Value : (A,1) added to storage.
    .....MENU.....
    1. Add
    2. remove key
    3. remove value
    4. display
    7. Exit
    Your choice :1
    
     Key : B
    
     Value : 2
    Key/Value : (B,2) added to storage.
    .....MENU.....
    1. Add
    2. remove key
    3. remove value
    4. display
    7. Exit
    Your choice :1
    
     Key : C
    
     Value : 3
    Key/Value : (C,3) added to storage.
    .....MENU.....
    1. Add
    2. remove key
    3. remove value
    4. display
    7. Exit
    Your choice :1
    
     Key : D
    
     Value : 4
    Key/Value : (D,4) added to storage.
    .....MENU.....
    1. Add
    2. remove key
    3. remove value
    4. display
    7. Exit
    Your choice :4
    ( D , 4 );
    ( A , 1 );
    ( B , 2 );
    ( C , 3 );
    .....MENU.....
    1. Add
    2. remove key
    3. remove value
    4. display
    7. Exit
    Your choice :2
    Key to REMOVE : 
    D
    Pair (D,4) Removed.
    .....MENU.....
    1. Add
    2. remove key
    3. remove value
    4. display
    7. Exit
    Your choice :4
    ( A , 1 );
    ( B , 2 );
    ( C , 3 );
    .....MENU.....
    1. Add
    2. remove key
    3. remove value
    4. display
    7. Exit
    Your choice :3
    Enter Value to remove : 2
    Key : B Removed.
    Exception in thread "main" java.util.ConcurrentModificationException
        at java.util.HashMap$HashIterator.nextEntry(HashMap.java:922)
        at java.util.HashMap$EntryIterator.next(HashMap.java:962)
        at java.util.HashMap$EntryIterator.next(HashMap.java:960)
        at TestHashMap.start(TestHashMap.java:60)
        at TestHashMap.main(TestHashMap.java:87)
    ABRT problem creation: 'success'
    

    code:

    import java.util.HashMap;
    import java.util.Map;
    import java.util.Scanner;
    
    class TestHashMap
    {
        private Map<String,Integer> map;
        public TestHashMap()
        {
            map = new HashMap<String,Integer>();
        }
        public void displayMenu()
        {
            System.out.println(".....MENU.....");
            System.out.println("1. Add");
            System.out.println("2. remove key");
            System.out.println("3. remove value");
            System.out.println("4. display");
            System.out.println("7. Exit");
            System.out.print("Your choice :");
        }
        public void start()
        {
            Scanner input = new Scanner(System.in);
            int menuChoice,value;
            String key;
            while(true)
            {
                displayMenu();
                menuChoice = input.nextInt();
                switch(menuChoice)
                {
                    case 1:
                        System.out.print("\n Key : ");
                        input.nextLine();
                        key = input.nextLine();
                        System.out.print("\n Value : ");
                        value = input.nextInt();
                        map.put(key,new Integer(value));
                        System.out.println("Key/Value : ("+key+","+value+") added to storage.");
                    break;
                    case 2:
                        System.out.println("Key to REMOVE : ");
                        input.nextLine();
                        key = input.nextLine();
                        Integer v = map.get(key);
                        if(v == null)
                            System.out.println("No value exists for key "+key);
                        else
                        {
                            map.remove(key);
                            System.out.println("Pair ("+key+","+v.intValue()+") Removed.");
                        }
                        break;
                    case 3:
                        System.out.print("Enter Value to remove : ");
                        value = input.nextInt();
                        if(map.containsValue(new Integer(value)))
                        {
                            for(Map.Entry<String,Integer> entry : map.entrySet() )
                            {
                                if(entry.getValue().intValue() == value)
                                {
                                    System.out.println("Key : "+entry.getKey()+" Removed.");
                                    map.remove(entry.getKey());
                                }
                            }
                        }
                    break;
                    case 4:
                        for(Map.Entry<String,Integer> entry : map.entrySet() )
                        {
                            System.out.println("( "+entry.getKey()+" , "+entry.getValue()+" );");
                        }
                    break;
                    case 7:
                        input.close();
                        System.exit(0);
                    default:
                        System.out.println("Invalid Choice !");
                }
            }
        }
        public static void main(String args[])
        {
            TestHashMap thm = new TestHashMap();
            thm.start();
        }
    }
    

    UPDATE: working code

    thanks to both (rgettman,Nathan Hughes) of you.

    import java.util.HashMap;
    import java.util.Map;
    import java.util.Scanner;
    import java.util.Iterator;
    
    class TestHashMap
    {
        private Map<String,Integer> map;
        public TestHashMap()
        {
            map = new HashMap<String,Integer>();
        }
        public void displayMenu()
        {
            System.out.println(".....MENU.....");
            System.out.println("1. Add");
            System.out.println("2. remove key");
            System.out.println("3. remove value");
            System.out.println("4. display");
            System.out.println("7. Exit");
            System.out.print("Your choice :");
        }
        public void start()
        {
            Scanner input = new Scanner(System.in);
            int menuChoice,value;
            String key;
            while(true)
            {
                displayMenu();
                menuChoice = input.nextInt();
                switch(menuChoice)
                {
                    case 1:
                        System.out.print("\n Key : ");
                        input.nextLine();
                        key = input.nextLine();
                        System.out.print("\n Value : ");
                        value = input.nextInt();
                        map.put(key,new Integer(value));
                        System.out.println("Key/Value : ("+key+","+value+") added to storage.");
                    break;
                    case 2:
                        System.out.println("Key to REMOVE : ");
                        input.nextLine();
                        key = input.nextLine();
                        Integer v = map.get(key);
                        if(v == null)
                            System.out.println("No value exists for key "+key);
                        else
                        {
                            map.remove(key);
                            System.out.println("Pair ("+key+","+v.intValue()+") Removed.");
                        }
                        break;
                    case 3:
                        System.out.print("Enter Value to remove : ");
                        value = input.nextInt();
                        if(map.containsValue(new Integer(value)))
                        {
                            for (Iterator<Map.Entry<String, Integer>> it = map.entrySet().iterator();it.hasNext();) 
                            {
                                Map.Entry<String,Integer> x = it.next();
                                if(x.getValue().intValue() == value)
                                {
                                    key = x.getKey();
                                    it.remove();
                                    System.out.println("Key : "+key+" Removed.");
                                }
                            }
                        }
                    break;
                    case 4:
                        for(Map.Entry<String,Integer> entry : map.entrySet() )
                        {
                            System.out.println("( "+entry.getKey()+" , "+entry.getValue()+" );");
                        }
                    break;
                    case 7:
                        input.close();
                        System.exit(0);
                    default:
                        System.out.println("Invalid Choice !");
                }
            }
        }
        public static void main(String args[])
        {
            TestHashMap thm = new TestHashMap();
            thm.start();
        }
    }
    
  • Julien
    Julien almost 9 years
    I prefer the version that uses while(it.hasNext()), as for loops are normally used for loop where the number of iteration are known in advance. Well I've been told so years ago at uni.
  • Nathan Hughes
    Nathan Hughes almost 9 years
    @Julien: sure, pretty much the same thing; only difference is the for loop keeps the scope of the iterator variable local to the for-block.