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

为何HashMap在大小未改变时仍抛出ConcurrentModificationException?

为什么HashMap大小没变化,迭代时还是抛出ConcurrentModificationException?

这个问题其实戳中了HashMap fail-fast机制的一个常见误解——它不是单纯检查集合大小有没有变化,而是靠内部的修改计数器来判断的!

先搞懂HashMap的fail-fast核心逻辑

HashMap内部维护了一个叫modCount的变量,它本质是个修改计数器:

  • 每次对HashMap做结构性修改(比如put、remove、clear,甚至包括覆盖已存在key的put操作),这个计数器都会自动加1
  • 当你创建迭代器(比如keySet().iterator()或者entrySet().iterator())时,迭代器会把当前的modCount值存到自己的expectedModCount变量里
  • 在迭代过程中,每次调用next()或者remove()时,迭代器都会检查modCount和expectedModCount是否相等。如果不等,直接抛出ConcurrentModificationException

回到你的场景:大小没变化但计数器变了

你说集合大小没变化却抛异常,大概率是在迭代过程中做了这种操作:调用HashMap的put方法覆盖已存在的key。举个具体的例子,你try块里的代码可能是这样的:

Iterator<String> iterator = myMap.keySet().iterator();
while (iterator.hasNext()) {
    String key = iterator.next();
    // 覆盖已存在的key,集合大小没变,但modCount会加1
    myMap.put(key, "updated value");
}

这时候:

  • 初始modCount是4(因为你put了4个元素)
  • 迭代器创建时expectedModCount也是4
  • 每次执行put,哪怕key已经存在,HashMap的modCount还是会自增(变成5、6...)
  • 当下一次调用iterator.next()时,发现modCount != expectedModCount,就抛出异常了

怎么避免这个问题?

如果需要在迭代时修改集合,必须通过迭代器自身的方法来操作,比如用迭代器的remove()方法:

Iterator<String> iterator = myMap.keySet().iterator();
while (iterator.hasNext()) {
    String key = iterator.next();
    if (key.equals("2")) {
        // 用迭代器的remove方法,会同步更新expectedModCount
        iterator.remove();
    }
}

这种情况下,迭代器在执行remove()时,会把自己的expectedModCount同步为最新的modCount,就不会触发异常了。

总结一下:HashMap的fail-fast机制盯的是修改次数,不是集合大小。只要你在迭代时绕开迭代器直接修改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.26 09:30:43