Reputation: 169
I have a map
Map<String, String> map = new HashMap<String, String>();
map.put("Pujan", "pujan");
map.put("Swati", "swati");
map.put("Manish", "manish");
map.put("Jayant", "jayant");
Iterator<Map.Entry<String, String>> itr = map.entrySet().iterator();
while(itr.hasNext()){
Entry<String,String> entry=(Entry<String, String>) itr.next();
map.put("Manish", "Updated");
}
I don't get an exception here (where I am trying to modify an existing key value "Manish"). But if I try to add a new key map.put("Manish123", "Updated")
I get ConcurrentModificationException
.
Upvotes: 4
Views: 163
Reputation: 4695
If you see the Javadoc for the modCount
field of a HashMap (in Java 8 HashMap.java source), you will see:
/**
* The number of times this HashMap has been structurally modified.
* Structural modifications are those that change the number of mappings in
* the HashMap or otherwise modify its internal structure (e.g.,
* rehash). This field is used to make iterators on Collection-views of
* the HashMap fail-fast. (See ConcurrentModificationException).
*/
Thus this field keeps the number of times there have been structural modifications to the map. The various iterators in this class throw the ConcurrentModificationException
(a better name could have been chosen) when the expected modification count expectedModCount
(which is initialized to modCount
when you construct this iterator, for example, at the line Iterator<Map.Entry<String, String>> itr = map.entrySet().iterator();
) does not match modCount
which is mutated any time there are structural modifications to the map (e.g. calling put
with a new entry, among other things). Note that different threads are not involved here. All of this can happen in one single thread, for example, when you remove entries from the map or add entries to it while iterating).
As you can now relate, remapping an existing key to a different value should not result in changes to the internal structure of the hash map (since it simply replaces the value associated with the key). And all you are doing is simply remapping the key Manish
to a value Updated
repeatedly as many times as there are entries in the map (which is 4 and is fixed for the duration of iteration). If, however, added or removed any key you will get the ConcurrentModificationException
.
This is analogous to the following code (Note: for illustration purposes only):
List<String> names = Arrays.asList("Larry", "Moe", "Curly");
int i = 0;
Iterator<String> strIter = names.iterator();
while (strIter.hasNext()) {
names.set(i, strIter.next() + " " + i); // value changed, no structural modification to the list
i += 1;
}
System.out.println(names);
which prints:
[Larry 0, Moe 1, Curly 2]
Upvotes: 0
Reputation: 23329
Because your aren't modifying the iterator
,
put
will mutate an existing entry in this case because a Map.Entry
with the same key already exists in the Map
.
Upvotes: 4
Reputation: 1185
According to Java API : Iterating over collection using Iterator is subject to ConcurrentModificationException if Collection is modified after Iteration started, but this only happens in case of fail-fast Iterators.
There are two types of Iterators in Java, fail-fast and fail-safe, check difference between fail-safe and fail-fast Iterator for more details.
Fail-Fast Iterators in Java
Difference between fail-safe vs fail-fast iterator in javaAs name suggest fail-fast Iterators fail as soon as they realized that structure of Collection has been changed since iteration has begun. Structural changes means adding, removing or updating any element from collection while one thread is Iterating over that collection. fail-fast behavior is implemented by keeping a modification count and if iteration thread realizes the change in modification count it throws ConcurrentModificationException.
Java doc says this is not a guaranteed behavior instead its done of "best effort basis", So application programming can not rely on this behavior. Also since multiple threads are involved while updating and checking modification count and this check is done without synchronization, there is a chance that Iteration thread still sees a stale value and might not be able to detect any change done by parallel threads. Iterators returned by most of JDK1.4 collection are fail-fast including Vector, ArrayList, HashSet etc
Fail-Safe Iterator in java
Contrary to fail-fast Iterator, fail-safe iterator doesn't throw any Exception if Collection is modified structurally while one thread is Iterating over it because they work on clone of Collection instead of original collection and that’s why they are called as fail-safe iterator. Iterator of CopyOnWriteArrayList is an example of fail-safe Iterator also iterator written by ConcurrentHashMap keySet is also fail-safe iterator and never throw ConcurrentModificationException in Java.
Upvotes: -1