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

使用forEach遍历ArrayList时仅更新2个元素的原因排查

问题分析:ArrayList.forEach修改元素值异常的原因

问题场景

创建一个初始全为0的ArrayList,后续所有元素变为1。尝试用forEach结合Lambda将所有元素改回0时,仅前2个元素被修改,最终结果为[0, 0, 1, 1, 1],代码如下:

// 创建大小为5、元素全为0的列表
List<Integer> freeFrame = new ArrayList<Integer>(Collections.nCopies(5, 0));

// 后续操作后,freeFrame变为 [1, 1, 1, 1, 1]

// 尝试将所有元素改回0
if(!freeFrame.contains(0))
    freeFrame.forEach((b) -> freeFrame.set(b, 0));

// 最终freeFrame = [0, 0, 1, 1, 1]

核心原因:Lambda参数是元素值而非索引

这是逻辑错误导致的结果,和增删元素触发的并发修改异常无关——forEach的Lambda参数b是列表中当前遍历到的元素值,不是元素的索引,你的修改逻辑完全偏离了预期。

具体执行过程拆解

初始状态:freeFrame = [1,1,1,1,1],满足!contains(0)的条件,进入forEach遍历:

  1. 第一次遍历:b = 1(第一个元素的值),执行set(1, 0),列表变为[1,0,1,1,1]
  2. 第二次遍历:b = 0(第二个元素的值),执行set(0, 0),列表变为[0,0,1,1,1]
  3. 第三次遍历:b = 1(第三个元素的值),执行set(1, 0),但该位置已经是0,无变化
  4. 第四、五次遍历:b都是1,重复执行set(1, 0),无任何实际修改

最终就得到了[0,0,1,1,1]的结果。

正确实现方式

方式1:普通索引循环(你已采用的方法)

if(!freeFrame.contains(0)) {
    for(int i = 0; i < freeFrame.size(); i++) {
        freeFrame.set(i, 0);
    }
}

方式2:用replaceAll方法(更简洁)

List.replaceAll专门用于批量修改元素值,逻辑清晰且代码简洁:

if(!freeFrame.contains(0)) {
    freeFrame.replaceAll(x -> 0);
}

方式3:结合索引的forEach(借助IntStream)

如果一定要用forEach风格且基于索引操作,可以用流处理生成索引范围:

if(!freeFrame.contains(0)) {
    IntStream.range(0, freeFrame.size()).forEach(i -> freeFrame.set(i, 0));
}

内容的提问来源于stack exchange,提问作者Chad Lanoway

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 13:45:30