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

为何在for-each循环中调用remove方法未抛出ConcurrentModificationException?

ArrayList<String> collection = new ArrayList<String>();
collection.add("Apple");
collection.add("Banana");
collection.add("Cherry");
for (String element : collection) 
{
    if (element.equals("Banana")) {
        collection.remove(element);
    }
}

问题

按照常规认知,在for-each循环中调用集合的remove方法应该抛出ConcurrentModificationException,但上述代码运行正常,并未出现预期的该异常,请问这是为什么?


解答

这是因为你移除的是集合的倒数第二个元素,刚好触发了ArrayList迭代器的实现细节,让异常没机会被抛出。

先拆解下for-each循环的本质:它底层依赖ArrayList的迭代器(Iterator)实现,迭代器内部维护了两个关键变量:

  • cursor:记录下一个要访问的元素索引
  • expectedModCount:记录迭代器创建时集合的修改次数,用来和集合实际的modCount对比,一旦不一致就抛出异常

咱们一步步走代码执行流程:

  1. 初始状态:集合size=3,cursor=0,expectedModCount=modCount=3
  2. 第一次循环:迭代器调用next(),cursor从0变为1,返回元素"Apple",不触发移除,循环继续
  3. 第二次循环:迭代器调用next(),cursor从1变为2,返回元素"Banana",此时调用collection.remove(),集合modCount变为4,size缩小为2
  4. 准备下一次循环:迭代器先调用hasNext(),判断cursor < size——此时cursor=2,size=2,条件不成立,循环直接终止,根本没机会走到下一次next()里的checkForComodification()(检查修改次数的方法),自然不会抛异常

要是你把代码改成移除第一个元素"Apple",或者集合里有更多元素、移除的不是倒数第二个,循环就会继续执行下一次next(),这时就会检测到modCount和expectedModCount不一致,抛出ConcurrentModificationException。

注意:这只是ArrayList迭代器的特殊场景,绝对不能依赖这个行为写代码!正确的做法是用迭代器自身的remove()方法,或者用普通for循环从后往前遍历,避免触发fail-fast机制。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 14:05:24