java遍历集合时直接调用集合的remove()会抛concurrentmodificationexception,正确做法是用iterator的remove()、list的removeif()或倒序索引删除;并发场景应使用copyonwritearraylist或concurrenthashmap。

在 Java 中遍历集合时直接调用 remove() 方法会导致 ConcurrentModificationException(并发修改异常),这是因为大多数集合(如 ArrayList、HashMap)的迭代器是“快速失败”(fail-fast)的,检测到结构被意外修改就会抛出异常。正确做法不是绕过检查,而是使用支持安全删除的机制。
用 Iterator 的 remove() 方法
这是最标准、最安全的方式。迭代器自带的 remove() 方法专为边遍历边删除设计,它会同步更新内部状态,避免触发异常。
- 必须在调用
next()之后、且只调用一次remove(),否则抛出IllegalStateException - 不能用集合自身的
remove(),只能用迭代器对象的remove() - 适用于所有实现了
Iterator接口的集合(ArrayList、LinkedList、HashSet等)
示例:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
List<string> list = new ArrayList(Arrays.asList("a", "b", "c", "b"));
Iterator<string> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if ("b".equals(s)) {
it.remove(); // ✅ 安全删除
}
}
// 结果:["a", "c"]
</string></string>用 for-each 循环?不行,但可用增强 for 的替代写法
增强 for 循环底层仍用迭代器,直接调用集合 remove() 会出错。不要这样写:
for (String s : list) {
if ("b".equals(s)) {
list.remove(s); // ❌ 抛 ConcurrentModificationException
}
}
如果坚持用类似风格,可改用 removeIf()(Java 8+),它是集合原生支持的批量安全删除方法:
- 基于内部迭代,不暴露外部迭代器,天然线程安全(单线程下)
- 语义清晰,代码简洁
- 返回是否发生删除(boolean)
示例:
list.removeIf("b"::equals); // ✅ 简洁安全
倒序 for 循环遍历删除
对 List 类型(尤其是 ArrayList),从后往前用索引删除,可避免下标偏移和并发修改检查:
- 不会触发迭代器检查,因为没用迭代器
- 删除元素不影响尚未访问的前面元素的索引
- 仅适用于
List,不适用于Set或Map
示例:
for (int i = list.size() - 1; i >= 0; i--) {
if ("b".equals(list.get(i))) {
list.remove(i); // ✅ 安全(仅限 List)
}
}
需要并发场景?考虑线程安全集合
如果多线程环境下既要遍历又要删除,普通集合即使加锁也难兼顾性能与正确性。此时应换用并发集合:
-
CopyOnWriteArrayList:遍历时操作的是快照,增删不影响当前迭代器(适合读多写少) -
ConcurrentHashMap:提供forEach、remove等安全组合操作,支持弱一致性遍历 - 注意:
CopyOnWriteArrayList.iterator().remove()是不支持的(抛UnsupportedOperationException)
示例(CopyOnWriteArrayList):
List<string> list = new CopyOnWriteArrayList(Arrays.asList("a", "b", "c"));
for (String s : list) { // 遍历安全
if ("b".equals(s)) {
list.remove(s); // 删除也安全,但开销大
}
}
</string>核心原则就一条:别在遍历时用集合自身的修改方法,优先选迭代器 remove()、removeIf() 或倒序索引删除;并发场景则交给专门设计的线程安全集合。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










