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

流与迭代中Concurrent Modification Exception行为差异及原因咨询

HashMap迭代修改行为差异解析:为什么三个示例表现不同?

要搞懂这三个示例的差异,核心要抓住HashMap的快速失败(fail-fast)机制以及不同遍历方式的校验逻辑:

HashMap内部用modCount记录集合的结构修改次数(新增、删除元素属于结构变化,修改已有元素的value不算),迭代器初始化时会保存当前的modCount到expectedModCount,后续每次调用next()时都会校验两者是否一致,不一致就抛出ConcurrentModificationException——但这是"尽最大努力"的检查,不是绝对触发。


示例1:增强for循环迭代values时新增元素未抛异常

增强for循环底层依赖HashMap的ValueIterator,它的遍历逻辑基于entrySet的迭代器。

初始Map只有1个元素,第一次迭代拿到value="1"后,执行put新增元素,此时modCount确实增加了,但迭代器的hasNext()会发现已经没有下一个元素需要遍历了,不会再调用next()方法——而modCount的校验只在next()中执行,所以这次修改不会触发异常。

如果初始Map有多个元素(比如同时put(1L,"1")和put(2L,"2")),迭代时新增元素就会抛出异常,因为迭代器还会继续调用next(),此时会检测到modCount和expectedModCount不一致。


示例2:Stream forEach新增元素抛出异常

Stream的forEach方法针对HashMap的values视图,使用的是延迟绑定且快速失败的spliterator。

当调用forEach时,spliterator会绑定当前的modCount,在遍历过程中,只要集合发生结构变化(新增元素会修改modCount),spliterator就会立即校验modCount,发现不一致后直接抛出ConcurrentModificationException。这和增强for循环的校验时机不同,Stream的校验更严格,只要结构变化就会触发。


示例3:Stream forEach更新原有元素未抛异常

这里的put操作是更新已有key的value,HashMap的put方法在key已存在时,只会替换value值,不会修改modCount——因为modCount只在集合结构变化(新增/删除元素)时才会增加,修改value不属于结构变化。

既然modCount没有变化,spliterator的校验就会通过,自然不会抛出异常。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 17:57:53