You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

迭代HashMap时remove()与put()方法的行为差异探究

为什么迭代HashMap时调用remove()和put()行为不同?

嘿,这个问题问到点子上了!这背后其实是HashMap迭代器的**fail-fast(快速失败)**机制在搞鬼,而且remove和put的行为差异,本质是它们对HashMap内部modCount的影响以及迭代器的检查时机不同。

先搞懂fail-fast的核心逻辑

HashMap内部维护了一个modCount变量,用来记录哈希表结构被修改的次数(比如新增、删除元素、扩容这些操作都会改变它)。当你通过keySet()、entrySet()获取迭代器时,迭代器会初始化一个expectedModCount变量,把当时的modCount值存进去。

之后每次调用迭代器的next()方法时,都会先检查modCount和expectedModCount是否相等:

  • 如果相等,正常返回下一个元素;
  • 如果不等,直接抛出ConcurrentModificationException(也就是我们常说的“并发修改异常”)——这就是fail-fast机制,用来防止迭代过程中哈希表结构被意外修改导致迭代器错乱。

为什么remove()有时候看起来“没事”,有时候又抛异常?

你代码里用的是myMap.remove("2")这种直接调用HashMap的remove方法,而不是迭代器的iterator.remove()。这种情况下:

  1. 调用myMap.remove()会让modCount加1,但迭代器的expectedModCount不会同步更新;
  2. 如果删除操作之后,迭代器已经没有下一个元素要遍历了(比如你删的是最后一个元素,或者循环刚好走到末尾),那么迭代器的hasNext()会返回false,循环直接结束,不会触发next()里的检查,所以看起来没抛异常;
  3. 但如果删除后还有元素要遍历,下一次调用next()时就会发现modCount != expectedModCount,立刻抛出异常。

⚠️ 注意:就算这次没抛异常,这种操作也是不安全的——迭代器的内部指针可能已经错乱,后续遍历可能出现遗漏或重复元素。正确的删除方式是用迭代器自己的remove()方法,它会在删除后同步更新expectedModCount = modCount,避免触发异常。

put()的行为为什么不一样?

put()方法对modCount的影响分两种情况:

  1. 替换已有元素:如果put的key已经存在,只是修改value,这种操作不会改变哈希表的结构,所以modCount不会变化。这时候迭代器的检查不会触发异常,看起来“没事”;
  2. 新增元素:如果put的key是新的,会触发哈希表结构变化(甚至可能触发扩容),modCount会加1。这时候只要迭代器后续调用next(),就会触发ConcurrentModificationException——而且因为新增元素可能改变哈希表的桶结构,迭代器的错乱会比删除更严重。

另外,就算你用迭代器的remove()方法,直接调用myMap.put()还是会触发异常,因为迭代器的方法只能处理自己的删除操作,管不了put带来的结构变化。

结合你的代码看具体场景

你在第一个循环里,当key是"3"时:

  • myMap.put("3new", "new3")是新增元素,modCount加1;
  • myMap.remove("2")是删除元素,modCount再加1;
    这时候modCount比迭代器初始化时的expectedModCount大2。当循环继续执行下一次next()时,就会触发并发修改异常。

正确的迭代修改姿势

如果要在迭代时安全修改HashMap,应该用迭代器的API:

Iterator<String> keyIterator = myMap.keySet().iterator();
while (keyIterator.hasNext()) {
    String key = keyIterator.next();
    if (key.equals("3")) {
        // 如果你必须新增元素,建议先收集要新增的内容,迭代结束后再批量put
        // myMap.put(key + "new", "new3"); // 这个操作依然会触发异常,除非是替换已有元素
        keyIterator.remove(); // 这个是安全的,会同步expectedModCount
    }
}

如果需要在迭代时新增元素,最好的方式是先把要新增的键值对存到一个临时集合里,等迭代完全结束后,再批量put到原HashMap中。

内容的提问来源于stack exchange,提问作者user2681668

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:01:40