循环遍历List时,对当前对象进行删除ConcurrentModificationException

本文探讨了在Java中从List中安全删除元素的方法。指出直接使用for循环结合list.remove(o)会导致ConcurrentModificationException异常,强调了正确做法是利用Iterator迭代器进行遍历并调用iter.remove()来进行删除。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

经常要根据条件判断删除List中的某些对象,实现方法都是用循环遍历List,然后用个IF之类的判断来remove

 

但是如果用for(Object o : list),并且list.remove(o)的方式来删除,会报java.util.ConcurrentModificationException

 

用for(int i=0; i<value; i++)的方式也不行

 

必须要用Iterator来遍历,并且iter.remove()才可以

<think>我们正在解决遍历List删除元素导致的ConcurrentModificationException问题。根据引用内容,我们知道这个异常是因为在遍历过程中直接调用List的remove方法导致modCount和expectedModCount不一致。下面给出几种安全删除的方法,并引用相关文献说明。根据引用[1]和[4]:在增强for循环(即迭代器遍历)中直接调用List的remove方法会抛出ConcurrentModificationException,因为modCount增加了但迭代器的expectedModCount没有更新。引用[2]和[3]指出:应该使用迭代器自己的remove方法,这样会同更新expectedModCount,从而避免异常。因此,我们推荐以下方法:1.使用迭代器遍历并调用迭代器的remove方法(最佳实践)2.Java8+使用removeIf方法(内部使用迭代器)3.使用普通for循环并调整索引(适用于ArrayList等随机访问列表)4.倒序遍历删除(避免索引错乱)5.使用并发集合(如CopyOnWriteArrayList,但注意性能)下面详细说明:</think>### 解决 Java 遍历 List 删除元素的 `ConcurrentModificationException` 问题 #### 📌 异常原因分析 当使用增强 for 循环或迭代器遍历 List 直接调用 `list.remove()`,会导致: ```java List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C")); for (String item : list) { if ("B".equals(item)) { list.remove(item); // ❌ 直接调用集合的 remove() } } ``` **触发异常机制**: 1. List 内部维护 `modCount`(修改计数器) 2. 迭代器维护 `expectedModCount`(预期修改值) 3. 直接调用 `list.remove()` 会使 `modCount++`,但 `expectedModCount` 未更新 4. 迭代器下次操作检测到 `modCount != expectedModCount` → 抛出异常[^1][^4] --- ### ✅ 安全删除元素的 5 种方案 #### 方案 1:使用迭代器的 `remove()`(最佳实践) ```java Iterator<String> it = list.iterator(); while (it.hasNext()) { String item = it.next(); if ("B".equals(item)) { it.remove(); // ✅ 同步更新 modCount 和 expectedModCount[^2][^4] } } // 结果:list → ["A", "C"] ``` #### 方案 2:Java 8+ 使用 `removeIf()`(最简洁) ```java list.removeIf(item -> "B".equals(item)); // ✅ 内部自动处理迭代器删除 ``` #### 方案 3:普通 for 循环 + 索引回退(适合 ArrayList) ```java for (int i = 0; i < list.size(); i++) { if ("B".equals(list.get(i))) { list.remove(i); i--; // ✅ 删除后索引回退[^3] } } ``` #### 方案 4:倒序遍历删除(避免索引错位) ```java for (int i = list.size() - 1; i >= 0; i--) { if ("B".equals(list.get(i))) { list.remove(i); // ✅ 倒序删除影响前方索引 } } ``` #### 方案 5:使用并发集合(线程安全场景) ```java List<String> safeList = new CopyOnWriteArrayList<>(list); for (String item : safeList) { if ("B".equals(item)) { safeList.remove(item); // ✅ 允许遍历修改(牺牲写性能) } } ``` --- ### ❌ 绝对禁止的操作 ```java // 错误 1:增强 for 循环中调用集合 remove() for (String item : list) { list.remove(item); // ❌ 必抛 ConcurrentModificationException[^1][^2] } // 错误 2:迭代器遍历中调用集合 remove() Iterator<String> it = list.iterator(); while (it.hasNext()) { String item = it.next(); list.remove(item); // ❌ 破坏 modCount 一致性[^4] } ``` --- ### 关键原则总结 1. **遍历删除必须通过迭代器自身**:调用 `iterator.remove()` 保持 `modCount` 和 `expectedModCount` 同步[^4] 2. **多线程环境**:优先使用 `CopyOnWriteArrayList` 或 `Collections.synchronizedList()` + 同步块 3. **Java 8+ 首选**:`removeIf()` 兼顾简洁性与安全性 4. **性能考量**: - 小集合:迭代器方案 - 大集合:先收集待删除元素,遍历后批量删除 > 通过正确使用迭代器控制修改操作,可完全避免 `ConcurrentModificationException`,同保证数据一致性[^2][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值