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

使用iterator.remove()仍抛出java.util.ConcurrentModificationException的原因与解决

问题原因与解决方案

首先直接给结论:不是迭代器“未感知”新增元素,而是它故意检测到这种外部修改就抛出异常。

ArrayList的迭代器属于「快速失败(fail-fast)」迭代器:当你创建迭代器后,它会记录当前集合的修改次数modCount,并把这个值存在自己的expectedModCount里。在迭代过程中,每次调用next()都会检查这两个值是否一致——如果不一致,就说明集合的结构(添加、删除元素)被迭代器以外的方式修改了(比如你直接调用list.add("6")),这时候迭代器就会抛出ConcurrentModificationException,防止因为并发修改导致的不确定遍历结果(哪怕你是单线程操作也会触发这个机制)。

而iterator.remove()之所以安全,是因为这个方法会在删除元素后同步更新expectedModCount,让它和集合的modCount保持一致。但list.add()不会做这个同步,所以迭代器下次检查时就会发现值不匹配,抛出异常。


接下来给你几个可行的解决方案:

方案1:使用ListIterator的add()方法(推荐,单线程场景最适配)

ListIterator是普通Iterator的子类,专门为List集合设计,它支持在迭代过程中安全添加、修改元素——因为listIterator.add()会同步更新expectedModCount,让迭代器感知到这次修改。示例代码:

public static void main(String args[]) {
    List<String> list = new ArrayList<>();
    list.add("1");
    list.add("2");
    list.add("3");
    list.add("4");
    list.add("5");
    
    // 用ListIterator替代普通Iterator
    ListIterator<String> it = list.listIterator();
    while (it.hasNext()) {
        String value = it.next();
        // 假设在某个条件下添加元素"6"
        if ("3".equals(value)) {
            it.add("6");
        }
    }
    
    System.out.println(list); // 输出: [1, 2, 3, 6, 4, 5]
}

方案2:先收集要添加的元素,迭代结束后批量添加

如果不想用ListIterator,可以先把需要添加的元素存到一个临时集合里,等迭代完全结束后,再一次性把临时集合的元素添加到原集合中。这样就不会在迭代过程中修改原集合的结构,自然不会触发异常:

public static void main(String args[]) {
    List<String> list = new ArrayList<>();
    list.add("1");
    list.add("2");
    list.add("3");
    list.add("4");
    list.add("5");
    List<String> toAddElements = new ArrayList<>();
    
    for (Iterator<String> it = list.iterator(); it.hasNext();) {
        String value = it.next();
        if ("3".equals(value)) {
            toAddElements.add("6");
        }
        // 这里依然可以安全使用it.remove()删除元素
    }
    
    // 迭代结束后批量添加
    list.addAll(toAddElements);
    System.out.println(list); // 输出: [1, 2, 3, 4, 5, 6]
}

方案3:使用CopyOnWriteArrayList(适合读多写少的并发场景)

如果是在多线程环境下,或者你希望迭代过程中允许直接修改集合但不抛异常,可以用java.util.concurrent.CopyOnWriteArrayList。它的迭代器是基于集合的快照创建的,迭代过程中不会检测集合的修改,不过修改操作(add/remove)会复制整个底层数组,所以适合读多写少的场景:

import java.util.concurrent.CopyOnWriteArrayList;
import java.util.Iterator;

public static void main(String args[]) {
    CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
    list.add("1");
    list.add("2");
    list.add("3");
    list.add("4");
    list.add("5");
    
    Iterator<String> it = list.iterator();
    while (it.hasNext()) {
        String value = it.next();
        if ("3".equals(value)) {
            list.add("6"); // 直接调用add不会抛异常
        }
    }
    
    System.out.println(list); // 输出: [1, 2, 3, 4, 5, 6]
    // 注意:迭代器遍历的是创建时的快照,所以迭代过程中看不到新增的"6"
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:57:44