WMX · 随记
·Java· 3 分钟阅读

遍历 ArrayList 时,如何安全删除元素

在增强 for 循环中直接调用 list.remove,常会触发 ConcurrentModificationException。名称里有 Concurrent,并不意味着一定发生了多线程。

▶ 本文含视频讲解
▶ 教学视频手动播放 · 英语讲解

Java Tutorial for Beginners

Java 基础课程作为语言背景复习;本文的特定 API、版本行为和边界条件以正文及文档为准。此为外部原版课程,多篇笔记可能共用;未剪辑为本文专属视频。

播放器需要能访问 YouTube 的网络;若这里无法加载,可打开原视频。本文与本地图解仍可独立阅读。

Java 系列概览:类型与值、状态与资源、边界验证
Java 系列概览:类型与值、状态与资源、边界验证 点击图片查看大图 ↗

问题从哪里出现

在增强 for 循环中直接调用 list.remove,常会触发 ConcurrentModificationException。名称里有 Concurrent,并不意味着一定发生了多线程。

理解核心机制

增强 for 通常使用迭代器。结构修改会破坏迭代器的预期状态。按条件删除可使用 removeIf;确实需要边遍历边删除时,应使用迭代器自己的 remove 方法,并遵守其调用顺序。

动手做一个小实验

Java 17 或更新版本;将示例保存为 Demo.java,执行 javac Demo.java 后运行 java Demo。

Java14 行 · 可横向滚动
import java.util.ArrayList;
import java.util.List;
public class Demo {
    public static void main(String[] args) {
        List<Integer> values = new ArrayList<>(List.of(1, 2, 3, 4));
        values.removeIf(value -> value % 2 == 0);
        System.out.println(values);
        var iterator = values.iterator();
        while (iterator.hasNext()) {
            if (iterator.next() > 2) iterator.remove();
        }
        System.out.println(values);
    }
}

适用边界与常见误区

fail-fast 只是尽力发现错误的机制,不应作为并发安全保障。不可修改集合会拒绝删除操作,多个线程修改普通 ArrayList 仍需要额外设计。

继续练习

加入连续两个待删除元素,比较正向索引删除与 removeIf 的结果;解释索引变化为何可能导致漏删。

参考资料

阅读相关官方文档或原始资料 ↗

← 返回文章归档