Search code examples
javaexceptionhashmapconcurrentmodification

getting concurrentmodification error while looping on hashmap


I have the following error:

Exception in thread "Thread-0" java.util.ConcurrentModificationException
at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1584)
at java.base/java.util.HashMap$KeyIterator.next(HashMap.java:1607)
at Server$1.run(Server.java:149)
at java.base/java.lang.Thread.run(Thread.java:832)

Reffering to this code:

    for (Session key : sessions.keySet()) {
                        if (key.getPort2() != port && key.getPort1() != port) { // change later to ip
                            System.out.println("2nd time init 2 client");

                            session.setIp2(ip);
                            session.setPort2(port);

                            sessionID++;

                            sessions.put(session, sessionID);

                            // reset session
                            session = null;

                        }
                    }

Could you explain why this happens?


Solution

  • You modify the map while you iterate over its content, which forbidden.

    Almost all collection classes forbid this for a good reason. Lets assume you have a collection which contains

    a b c g h i j k l
    

    Now you iterate over the elements and while processing element k you insert d. Would you expect that d is skipped because you are already bejond that position? What if you are at position b and insert an m? Would you expect that m will be processed? Or would you expect that new elements will not be processed because they did not exist at the time when you started iterating?

    If Java would allow that, people would complain about unexpected behavior. And that is the reason why Java does not allow it. It is one major goal of Java to avoid unexpected behavior, compared to older programming languages.

    To solve this, create a second temporary empty map before you start iterating. Then inside your loop you can put new elements into that temporary map. Then finally combine them:

    Map<String, String> tmp=new HashMap<>();
    for (Session key : sessions.keySet()) {
       ...
       tmp.put(session, sessionID);
    }
    sessions.putAll(tmp);
    

    This way it is clear what happens, no unexpected behavior.