 报 ConcurrentModificationException 怎么解决?)
Java List.remove() 报 ConcurrentModificationException 怎么解决问题分析你在循环中调用list.remove()时遇到了ConcurrentModificationException异常。这是 Java 集合框架中非常经典的一个坑在遍历集合的过程中直接修改集合结构增删元素会触发快速失败fail-fast机制。错误堆栈类似这样Exception in thread main java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909) at java.util.ArrayList$Itr.next(ArrayList.java:859)先看一段典型的错误代码你大概率是这样写的import java.util.ArrayList; import java.util.List; public class BadRemoveExample { public static void main(String[] args) { ListString list new ArrayList(); list.add(A); list.add(B); list.add(C); list.add(B); // 错误写法在增强for循环中直接remove for (String s : list) { if (s.equals(B)) { list.remove(s); // 这里抛出ConcurrentModificationException } } System.out.println(list); } }排查步骤1. 确认你的代码结构检查你的代码是否属于以下模式- 使用for-each循环或Iterator遍历时直接调用list.remove()- 使用普通for循环时删除后没有调整索引可能导致漏删或越界- 多个线程同时修改同一个 List这种情况需要额外加锁本文不展开2. 理解异常原因ArrayList内部维护了一个modCount字段记录结构修改次数。当创建迭代器时迭代器会记住当前的modCount。每次迭代器调用next()时都会检查modCount是否改变。如果改变了比如你直接调用了list.remove()就会抛出ConcurrentModificationException。示例代码方案一使用迭代器Iterator的 remove() 方法这是最传统、最安全的做法。迭代器自己提供的remove()方法会同步更新modCount不会触发异常。import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class IteratorRemoveExample { public static void main(String[] args) { ListString list new ArrayList(); list.add(A); list.add(B); list.add(C); list.add(B); // 正确做法使用迭代器的remove方法 IteratorString iterator list.iterator(); while (iterator.hasNext()) { String s iterator.next(); if (s.equals(B)) { iterator.remove(); // 安全删除 } } System.out.println(迭代器方案结果: list); // 输出: [A, C] } }方案二使用 Java 8 的 removeIf() 方法推荐如果你的环境是 Java 8 及以上removeIf()是最简洁的方案。它内部已经处理了并发修改问题一行代码搞定。import java.util.ArrayList; import java.util.List; public class RemoveIfExample { public static void main(String[] args) { ListString list new ArrayList(); list.add(A); list.add(B); list.add(C); list.add(B); // 一行代码搞定删除所有等于B的元素 list.removeIf(s - s.equals(B)); System.out.println(removeIf方案结果: list); // 输出: [A, C] } }方案三普通 for 循环 索引调整不推荐但可用如果你坚持用for循环记得删除后索引减1否则会漏掉连续重复的元素。import java.util.ArrayList; import java.util.List; public class ForLoopRemoveExample { public static void main(String[] args) { ListString list new ArrayList(); list.add(A); list.add(B); list.add(B); // 连续重复元素测试漏删问题 list.add(C); // 倒序遍历避免索引问题推荐 for (int i list.size() - 1; i 0; i--) { if (list.get(i).equals(B)) { list.remove(i); } } System.out.println(for循环倒序删除结果: list); // 输出: [A, C] } }运行说明1.环境要求JDK 8 及以上removeIf需要 Java 82.直接复制运行以上代码都包含完整的main方法直接粘贴到 IDE 或命令行即可运行3.修改条件将s.equals(B)替换为你自己的删除条件即可常见坑坑1增强 for 循环中删除for (String s : list) { if (s.equals(B)) { list.remove(s); // ❌ 抛出异常 } }原因增强 for 循环本质是迭代器直接调用list.remove()会修改modCount导致迭代器检测到不一致。坑2普通 for 循环删除后索引不调整for (int i 0; i list.size(); i) { if (list.get(i).equals(B)) { list.remove(i); // ❌ 漏删删除后元素前移i会跳过下一个元素 } }解决方案删除后i--或者倒序遍历。坑3多线程环境直接使用以上方案如果多个线程同时修改同一个 List以上方案仍然不安全。需要加锁或使用CopyOnWriteArrayList。性能对比-迭代器方案时间复杂度 O(n)适合任意删除条件-removeIf底层也是迭代器性能相近代码更简洁-for循环倒序同样 O(n)但代码可读性稍差建议日常开发直接用removeIf需要更复杂的删除逻辑如删除前需要额外操作用迭代器方案。还有问题可以把报错贴评论区这类集合操作在写小工具或自动化脚本时很常见多练几次就熟悉了。