LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

list可以一边遍历一边修改元素吗?

zhenglin
2026年2月7日 11:36 本文热度 75

List可以一边遍历一边修改元素吗?

核心答案

List能否边遍历边修改,取决于两个因素:

  1. 集合的实现机制(fail-fast 或 fail-safe)

  2. 遍历的方式(增强for、Iterator、索引遍历等)


详细分析

1. fail-fast集合(ArrayList、LinkedList)

1.1 什么是fail-fast?
  • 定义:快速失败机制,在检测到并发修改时立即抛出异常

  • 实现:通过modCount计数器检测结构性修改

  • 目的:避免在并发修改时产生不确定的行为

1.2 不同遍历方式的表现
增强for循环 - 不能修改

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));


// 抛出 ConcurrentModificationException

for (String item : list) {

    if ("B".equals(item)) {

        list.remove(item); // ❌ 异常!

    }

}

Iterator遍历 - 有条件修改

Iterator<String> iterator = list.iterator();

while (iterator.hasNext()) {

    String item = iterator.next();

    if ("B".equals(item)) {

        // list.remove(item);  // ❌ 直接修改集合会抛异常

        iterator.remove();     // ✅ 使用Iterator的remove方法

    }

}

索引遍历 - 可以修改(需注意索引)

// 方式1:正序遍历(需要手动调整索引)

for (int i = 0; i < list.size(); i++) {

    if ("B".equals(list.get(i))) {

        list.remove(i);

        i--; // 重要:调整索引

    }

}


// 方式2:倒序遍历(推荐)

for (int i = list.size() - 1; i >= 0; i--) {

    if ("B".equals(list.get(i))) {

        list.remove(i); // 不需要调整索引

    }

}

Stream forEach - 不能修改
代码高亮:

list.stream().forEach(item -> {

    if ("B".equals(item)) {

        list.remove(item); // ❌ ConcurrentModificationException

    }

});

1.3 fail-fast原理解析

public abstract class AbstractList<E> {

    // 修改次数计数器

    protected transient int modCount = 0;

    

    private class Itr implements Iterator<E> {

        // 迭代器创建时记录的modCount

        int expectedModCount = modCount;

        

        public E next() {

            checkForComodification(); // 每次调用都检查

            // ... 返回元素

        }

        

        final void checkForComodification() {

            if (modCount != expectedModCount)

                throw new ConcurrentModificationException();

        }

        

        public void remove() {

            // ... 执行删除

            expectedModCount = modCount; // 同步modCount

        }

    }

}

2. fail-safe集合(CopyOnWriteArrayList)

2.1 什么是fail-safe?
  • 定义:安全失败机制,允许在遍历时修改集合
  • 实现:遍历的是集合的快照(副本)
  • 特点:修改对当前遍历不可见
2.2 所有遍历方式都可以修改
增强for循环

List<String> list = new CopyOnWriteArrayList<>(Arrays.asList("A", "B", "C"));


for (String item : list) {

    if ("B".equals(item)) {

        list.remove(item); // ✅ 不会抛异常

        list.add("D");     // ✅ 可以添加(但当前遍历看不到)

    }

}

// 遍历看到: A, B, C

// 最终结果: [A, C, D]

Iterator遍历

Iterator<String> it = list.iterator();

while (it.hasNext()) {

    String item = it.next();

    if ("B".equals(item)) {

        list.remove(item);     // ✅ 可以

        // it.remove();         // ⚠️ 注意:不支持Iterator.remove()

    }

}

2.3 fail-safe原理解析
代码高亮:

public class CopyOnWriteArrayList<E> {

    private volatile Object[] array;

    

    // 写操作:创建新数组

    public E remove(int index) {

        final ReentrantLock lock = this.lock;

        lock.lock();

        try {

            Object[] elements = getArray();

            Object[] newElements = new Object[elements.length - 1];

            // ... 复制数组,排除要删除的元素

            setArray(newElements); // 替换引用

            return oldValue;

        } finally {

            lock.unlock();

        }

    }

    

    // 读操作:返回快照迭代器

    public Iterator<E> iterator() {

        return new COWIterator<E>(getArray(), 0);

    }

    

    static final class COWIterator<E> implements Iterator<E> {

        private final Object[] snapshot; // 持有数组快照

        

        private COWIterator(Object[] elements, int initialCursor) {

            snapshot = elements;

        }

    }

}


总结记忆

 

参考文章:原文链接


该文章在 2026/2/7 11:36:35 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved