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:
- You create a
HashMap.
- You add one entry to it.
- You begin an iteration.
hasNext is true, so you go into the body of your loop.
- 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.
- You add to the map.
- 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").
m.putwhile iterating over the map. Shouldigo to the keydsad, or not?