HashMap中的@ConcurrentModificationException如何解决?

3

我预期在以下代码中会出现ConcurrentModificationException,但实际上它正在正常运行。

HashMap<Integer, String>table1 = new HashMap<Integer, String>();
    table1.put(1, "Sam");
    table1.put(2, "Jon");
    table1.put(3, "Doe");

    Iterator itr1 = table1.entrySet().iterator();

    table1.put(3, "DONN");
    while(itr1.hasNext())
    {
        System.out.println("---Value--" + itr1.next());
    }

根据 JavaDoc 中对于 HashMap 的说明:
所有 "collection view methods" 返回的迭代器都是 fail-fast 的:如果在创建迭代器之后,以除迭代器自身的 remove 方法外的任何方式对映射进行结构性修改,则迭代器将抛出 ConcurrentModificationException。
因此,既然在获取 Iterator 后修改了 HashMap,我应该会收到 ConcurrentModificationException。为什么没有抛出异常呢?

1
文档还指出:“快速失败的迭代器会尽最大努力抛出ConcurrentModificationException异常。因此,编写依赖于此异常正确性的程序是错误的:迭代器的快速失败行为仅应用于检测错误。” - kiheru
3个回答

3

在当前实现的HashMap中,为已存在的键添加条目不被视为结构修改,并且永远不会触发ConcurrentModificationException。尝试使用新键进行添加,例如table1.put(4, "UPS");,以获得ConcurrentModificationException


2
您正在修改的是HashMap而不是获取的entrySet,并且在这里您正在获取entrySet上的iterator
根据entrySet方法的JavaDoc:
如果在集合上进行迭代时修改了映射(除非通过迭代器自己的删除操作或通过迭代器返回的映射条目上的setValue操作),则迭代的结果未定义。
因此,您将不会收到ConcurrentModificationException
以下是entrySet的完整说明:
返回此映射中包含的映射的Set视图。该集合由映射支持,因此对映射的更改会反映在集合中,反之亦然。如果在集合上进行迭代时修改了映射(除非通过迭代器自己的删除操作或通过迭代器返回的映射条目上的setValue操作),则迭代的结果未定义。该集合支持元素删除,该操作通过Iterator.remove、Set.remove、removeAll、retainAll和clear操作从映射中删除相应的映射。它不支持add或addAll操作。

“undefined”并不意味着不会抛出ConcurrentModificationException异常,在当前实现中,它确实会抛出ConcurrentModificationException异常,但仅在添加或删除键时才会抛出。 - Holger
2
好的,明白了,因为他使用相同的键,所以HashMap没有被修改。 - Zeeshan

2

尝试使用table1.put(4, "DONN"),迭代器将会因为ConcurrentModificationException而失败。而table1.put(3, "DONN")并不会改变地图结构,只是替换了键为3的值,因为它已经存在。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接