遍历时直接调用arraylist.remove()会抛concurrentmodificationexception,因modcount校验失败;正确方式是用iterator.remove()或倒序遍历、removeif()等安全方案。

在 Java 中对 ArrayList 进行遍历时直接调用 remove() 方法删除元素,会抛出 ConcurrentModificationException(并发修改异常),这不是线程安全问题,而是 ArrayList 的快速失败(fail-fast)机制在起作用。
为什么遍历时删除会报错
ArrayList 内部维护了一个 modCount(修改计数器),每次调用 add()、remove() 等结构性修改方法时都会递增它。而迭代器(如 for-each 或 iterator())在创建时会记录当时的 modCount 值为 expectedModCount。每次调用 next() 或 hasNext() 时,都会检查二者是否一致;不一致就立即抛出 ConcurrentModificationException,防止遍历逻辑错乱或数据不一致。
注意:即使单线程下,只要“遍历中用集合自身删”,也会触发该检查 —— 这是设计上的保护机制,不是 bug。
正确删除方式:使用 Iterator.remove()
迭代器提供了安全的删除方法:Iterator.remove()。它会在删除元素的同时同步更新 expectedModCount,避免校验失败。
- ✅ 正确写法(推荐):
<br> List<string> list = new ArrayList(Arrays.asList("a", "b", "c", "b"));<br> Iterator<string> it = list.iterator();<br> while (it.hasNext()) {<br> String s = it.next();<br> if ("b".equals(s)) {<br> it.remove(); // 安全!<br> }<br> }<br></string></string>
- ❌ 错误写法(for-each 中调用 list.remove()):
<br> for (String s : list) {<br> if ("b".equals(s)) {<br> list.remove(s); // 报 ConcurrentModificationException<br> }<br> }<br>
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
其他安全方案(按场景选用)
-
倒序 for 循环:从
size-1往 0 遍历,删除不影响后续索引
<br> for (int i = list.size() - 1; i >= 0; i--) {<br> if ("b".equals(list.get(i))) {<br> list.remove(i);<br> }<br> }<br>
- 收集待删元素,遍历结束后统一删:适合条件复杂或需多次判断的场景
<br> List<string> toRemove = new ArrayList();<br> for (String s : list) {<br> if ("b".equals(s)) {<br> toRemove.add(s);<br> }<br> }<br> list.removeAll(toRemove);<br></string>
- JDK 8+ 的 removeIf():简洁、内部已用迭代器安全实现
<br> list.removeIf(s -> "b".equals(s));<br>
不推荐但需知道的误区
有人尝试用普通 for 循环正向遍历 + remove(),但不调整索引,会导致漏删:
<br> // ❌ 危险!删除后元素前移,i++ 会跳过下一个<br> for (int i = 0; i if ("b".equals(list.get(i))) {<br> list.remove(i); // 删除位置 i 后,原 i+1 元素移到 i,但 i 已自增 → 漏判<br> }<br> }<br>
若坚持正向 for,必须手动控制索引:if (match) { list.remove(i--); },但易出错,不建议。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










