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

HashMap迭代时新增key为0为何触发ConcurrentModificationException

问题底层原因分析

核心前置知识点:HashMap的fail-fast机制

HashMap内部维护了一个modCount变量,每次发生结构型变更(新增/删除键值对、触发扩容等操作)时,modCount的值会自增1。
当调用keySet().iterator()生成迭代器时,迭代器会将当前的modCount的值赋值给自己的成员变量expectedModCount。每次调用迭代器的next()方法获取下一个元素前,都会先校验expectedModCount == modCount是否成立,如果不成立就会直接抛出java.util.ConcurrentModificationException。
注意:如果是修改已存在key对应的value,不属于结构型变更,不会修改modCount的值。


各个场景的具体原因解释

1. 原代码put(1,2)不报错的原因

key=1是HashMap初始化时已经存在的键,此时调用map.put(1,2)属于修改已存在key的value,不会触发modCount更新,迭代器每次校验时expectedModCount和modCount始终一致,因此不会抛出异常。

2. 改为put(0,2)抛出异常的原因

key=0是HashMap中不存在的新键,调用map.put(0,2)属于新增键值对的结构型变更,会导致modCount自增1。
此时初始化的HashMap有3个元素(key1、2、3),迭代顺序为1→2→3:

  • 迭代到key=2时执行新增操作,modCount已经变更
  • 后续还需要调用next()获取第三个元素key=3,触发校验时发现两个计数不一致,直接抛出异常
    所有不存在的新key(包括小于0的负数key)执行put操作都会触发结构变更,因此都会出现相同问题。

3. 删除初始化的map.put(3,3)后运行正常的原因

删除第三个元素后,HashMap中只有key1、2两个元素,迭代顺序为1→2:

  • 迭代到key=2时执行新增操作,modCount虽然变更
  • 本轮next()已经执行完,后续判断it.hasNext()会返回false,循环直接结束,不会再调用next()触发校验逻辑,因此不会抛出异常。
    注意这属于极端场景下的巧合,不是合法的操作方式,线上环境绝对不能依赖这个特性写代码。

正确的遍历过程中修改HashMap的方式是使用迭代器自带的remove()方法,如果需要新增元素建议先把要新增的键值对暂存到另一个集合,遍历结束后再批量插入。

内容的提问来源于stack exchange,提问作者m.antkowicz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 16:57:00