2

I am trying to add a key value pair to the hashmap inside the Iterator method.

But this is not giving me ConcurrentModificationException . Why?

Since Hashmap is failfast.

Map<String,String> m = new HashMap<>();
           m.put("a", "a");

           Iterator<String> i = m.keySet().iterator();
           while(i.hasNext()){
               System.out.println(i.next());
               m.put("dsad", "asfsdf");

           }

If this is wrong, How i can produce ConcurrentModificationException ? Thanks.

Update: Just checked.

Map<String,String> m = new HashMap<>();
               m.put("a", "a");
          m.put("abc", "a");

               Iterator<String> i = m.keySet().iterator();
               while(i.hasNext()){
                   System.out.println(i.next());
                   m.put("dsad", "asfsdf");

               }

This is giving me the exception.

1
  • Your problem is calling m.put while iterating over the map. Should i go to the key dsad, or not? Commented Aug 26, 2013 at 19:43

3 Answers 3

3

It happens that the concurrent modification check done by the HashMap code fails to detect this situation. The code for HashMap's iterator's hasNext in Oracle's JDK7 is:

public final boolean hasNext() {
    return next != null;
}

...where (confusingly!) that next is a private data member in the iterator class (not to be confused with the next method on the Iterator interface — to my mind, calling that data member next was a very poor choice).

Note that it doesn't do the check for concurrent modifications. Contrast with this code that is called (indirectly) from Iterator#next:

    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();

...which does do the check.

So here's what happens in your code:

  1. You create a HashMap.
  2. You add one entry to it.
  3. You begin an iteration.
  4. hasNext is true, so you go into the body of your loop.
  5. You get the element from next; at this point, the iterator remembers what the next element should be on its internal data member (the confusingly-named next), and in this case since there's no next element in the map, that next data member is set to null, meaning that the iteration is complete.
  6. You add to the map.
  7. Your code calls hasNext, which sees the next data member is null and returns false.

If you had two elements in the map before starting your loop instead of one, you'd get the exception (from next).

I've previously argued this is, or is very nearly, a bug, but it's a pretty fuzzy area, and others have argued quite reasonably that it isn't. The documentation doesn't say specifically which methods of Iterator<E> will throw the exception, just that it will get thrown. The documentation also says it's only thrown on a "best effort" basis, it's not guaranteed.

Whether one considers this a bug or not, it's unlikely to be changed at this point, as the pain of changing it (breaking some existing code that probably shouldn't have relied on this behavior) far outweighs the benefit (possibly being more "correct").

Sign up to request clarification or add additional context in comments.

2 Comments

Why this is not a bug?
@Raj: Well, I think it is a bug. I've update the answer with some of the reasoning, and a deeper explanation of what's happening in your example.
0

The iterator may throw ConcurrentModificationException but is not guaranteed to.

From the javadoc of HashMap:

Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.

Comments

0

Try this:

  Map<String,String> m = new HashMap<>();
    m.put("a", "a");

    Iterator<String> i = m.keySet().iterator();
    while(i.hasNext()){
        m.remove("a");
        System.out.println(i.next());


    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.