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

为什么在for循环中删除元素时不总是抛出ConcurrentModificationException

三种遍历删除ArrayList元素结果差异的原因

首先明确核心基础原理:
ArrayList的fail-fast机制依赖两个核心变量:

  • modCount:记录集合结构修改的次数,add、remove等变更结构的操作都会让这个值+1
  • expectedModCount:迭代器初始化时会把当前的modCount赋值给这个变量,每次调用迭代器的next()方法时都会校验两个值是否相等,不等就抛出ConcurrentModificationException
    增强for循环的底层就是迭代器实现,普通for循环是自行通过索引访问,不涉及迭代器的校验逻辑。

场景1:普通for循环删除值为1的元素,输出[2,3]

普通for循环没有使用迭代器,不会触发modCount校验逻辑:

ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(2);
list.add(3);
for (int i = 0; i < list.size(); i++) {
    Integer integer = list.get(i);
    if (integer.equals(1)) {
        list.remove(integer);
    }
}
System.out.println(list);

执行逻辑:

  • 初始size=3,i=0时拿到元素1,匹配删除后列表变为[2,3],size更新为2
  • i自增到1,此时1 < 2,get(1)拿到元素3,不匹配删除条件
  • 循环结束,最终输出[2,3]
    注:普通for循环遍历删除存在元素漏判的隐患,比如要删除值为2的元素,删除后元素3会前移到索引1的位置,i自增到2就会直接结束循环,漏掉对元素3的校验

场景2:增强for循环删除值为1的元素,抛出ConcurrentModificationException

增强for循环底层走迭代器逻辑,会触发校验:

for (Integer integer : list) {
  if (integer.equals(1)) {
    list.remove(integer);
  }
}
System.out.println(list);

执行逻辑:

  • 迭代器初始化时expectedModCount = modCount = 3(三次add操作)
  • 第一次调用next()拿到元素1,匹配删除条件,调用list.remove()会让modCount变为4,但expectedModCount还是3
  • 下一轮循环先调用hasNext(),此时cursor=1,size=2,cursor != size返回true,继续调用next(),此时校验发现modCount != expectedModCount,直接抛出异常

场景3:增强for循环删除值为2的元素,输出[1,3]

这是迭代器边界判断的特殊情况,没有触发校验逻辑:

for (Integer integer : list) {
  if (integer.equals(2)) {
    list.remove(integer);
  }
}
System.out.println(list);

执行逻辑:

  • 迭代器初始化时expectedModCount = modCount = 3
  • 第一次调用next()拿到元素1,不匹配,cursor变为1
  • 第二次调用next()拿到元素2,匹配删除条件,调用list.remove()后列表变为[1,3],size更新为2,modCount变为4,cursor变为2
  • 下一轮循环调用hasNext(),判断逻辑是cursor != size,此时cursor=2,size=2,返回false,循环直接结束,不会调用next(),也就不会触发modCount校验,所以不会抛异常,最终输出[1,3]

推荐的安全遍历删除方式

如果要避免异常,推荐两种标准写法:

  1. 显式使用迭代器的remove()方法:
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
    Integer integer = iterator.next();
    if (integer.equals(1)) {
        iterator.remove(); // 该方法会同步更新expectedModCount,避免校验不通过
    }
}
  1. Java 8及以上版本使用removeIf()方法:
list.removeIf(integer -> integer.equals(1));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 08:15:04