concurrentmodificationexception单线程遍历时乱删元素也会触发,因java集合采用fail-fast机制;推荐iterator.remove()、removeif()、并发集合或暂存待删项统一处理。

ConcurrentModificationException不是“并发”才出的问题,单线程遍历时乱删元素也会触发。核心在于:Java集合(如ArrayList、HashMap)采用快速失败(fail-fast)机制,一旦迭代器发现集合结构被意外修改(比如modCount不匹配),就立刻抛异常,防止数据错乱或越界。
用Iterator的remove()安全删元素
这是单线程下最直接、最稳妥的方式。它和集合自身的remove()完全不同——Iterator的remove()会同步更新内部状态,避免校验失败。
- 必须在调用next()之后、下一次next()之前调用,否则抛IllegalStateException
- 不能在增强for循环里用,因为无法拿到Iterator对象
- 示例:it.remove() ✅;list.remove(item) ❌
改用removeIf()批量过滤(推荐Java 8+)
一行代码替代手动遍历+判断+删除,语义清晰、线程安全(单线程)、底层仍基于Iterator,但封装更优雅。
- 适用于List、Set等支持该方法的集合
- 写法简洁:list.removeIf(x -> x.startsWith("A"))
- 比“先收集再删”更省内存,也比手写Iterator更少出错
多线程场景优先选并发集合
别硬扛同步锁。CopyOnWriteArrayList适合读远多于写的列表(如监听器列表);ConcurrentHashMap适合高并发Map操作。
- CopyOnWriteArrayList允许遍历时安全add/remove,但写操作开销大,不适合高频写
- ConcurrentHashMap的keySet()/values()等视图迭代时不会抛此异常,但注意:computeIfAbsent等方法仍需按文档使用
- Vector或Collections.synchronizedList只是加了synchronized,遍历时仍要手动同步整个块,不推荐
遍历前暂存待删项,统一处理
当逻辑复杂、不能用removeIf,又不想引入并发集合时,这是一种通用兜底策略。
- 新建临时集合(如ArrayList或HashSet)存放要删的元素
- 遍历原集合只做判断和收集,不修改原集合
- 遍历结束后调用list.removeAll(toRemove)或逐个remove
- 注意:若原集合是HashSet,用HashSet存待删项可提升removeAll效率
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











