在 java 中,循环中修改集合大小导致 concurrentmodificationexception 时,应使用 iterator.remove() 方法、copyonwritearraylist 或 removeif() 来处理。直接调用集合的 remove() 会破坏迭代器的内部状态检查机制,从而抛出异常。

为什么直接 remove 会触发异常
当使用增强 for 循环(即 for-each)遍历集合时,底层使用的是迭代器。如果在循环体内直接调用集合对象的 remove() 方法,集合内部的 modCount 会增加,但迭代器的 expectedModCount 不会同步更新。当下一次迭代调用 next() 时,迭代器检测到这两个计数不一致,就会抛出 ConcurrentModificationException。

import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<string> list = new ArrayList();
list.add("A");
list.add("B");
list.add("C");
// 错误示范:直接调用 list.remove() 会导致 ConcurrentModificationException
try {
for (String item : list) {
if (item.equals("B")) {
list.remove(item); // 这里会抛出异常
}
}
} catch (Exception e) {
System.out.println("Caught: " + e.getClass().getSimpleName());
}
}
}</string>
运行上述代码将输出:
Caught: ConcurrentModificationException
如何安全地移除元素
要安全地在遍历过程中移除元素,最推荐的方式是使用迭代器的 remove() 方法。该方法会在移除元素的同时更新迭代器的内部状态,保持 modCount 和 expectedModCount 的一致性。对于 Java 8 及以上版本,也可以使用 List.removeIf() 方法,它通过 Predicate 过滤掉不需要的元素,完全避免了并发修改的问题。

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class SafeRemove {
public static void main(String[] args) {
List<string> list = new ArrayList();
list.add("A");
list.add("B");
list.add("C");
// 方法一:使用 Iterator.remove()
Iterator<string> it = list.iterator();
while (it.hasNext()) {
String item = it.next();
if (item.equals("B")) {
it.remove(); // 安全移除
}
}
System.out.println("After Iterator remove: " + list);
// 重置列表用于演示方法二
list.clear();
list.add("A");
list.add("B");
list.add("C");
// 方法二:使用 removeIf (Java 8+)
list.removeIf(item -> item.equals("B"));
System.out.println("After removeIf: " + list);
}
}</string></string>
运行结果:
After Iterator remove: [A, C]
After removeIf: [A, C]
不同集合类型的并发修改处理差异
除了标准的 ArrayList 和 LinkedList,在处理并发场景或需要频繁读写的集合时,可以选择 CopyOnWriteArrayList。该集合在写入时会创建底层数组的副本,因此遍历过程中对集合的修改不会影响当前迭代器,也不会抛出异常。这在读多写少的场景下非常有效,但需要注意其内存开销和最终一致性语义。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











