不能在 for-each 循环中直接调用 list.remove(),因为会触发 concurrentmodificationexception;for-each 基于 fail-fast 迭代器,直接调用集合 remove() 会使 modcount 与 expectedmodcount 不一致。

为什么不能在 for-each 循环里直接调用 list.remove()
因为会抛 ConcurrentModificationException。Java 的 ArrayList、LinkedList 等集合的迭代器是“快速失败”(fail-fast)的,for-each 本质就是用 Iterator,但你在遍历时绕过它、直接调用集合自身的 remove(),修改计数器(modCount)和预期值(expectedModCount)就对不上了。
常见错误现象:
– 遍历到某元素时突然报 java.util.ConcurrentModificationException
– 删除不全:只删了第一个匹配项就中断了
- 别写
for (String s : list) { if (s.isEmpty()) list.remove(s); } - 也别用普通
for (int i = 0; i 正向遍历 + <code>remove(),因为remove()后索引会前移,容易跳过下一个元素
必须用 Iterator.remove(),且只能紧跟在 next() 之后
Iterator.remove() 是唯一被设计为在遍历时安全删除的方法——它会同步更新 expectedModCount,避免校验失败。
使用场景:需要根据条件逐个判断并删除(比如过滤空字符串、过期对象、满足某 predicate 的元素)
关键约束:
– 必须先调用 next()(即已拿到当前元素),才能调用 remove()
– 一次 next() 后最多调用一次 remove();重复调用会抛 IllegalStateException
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
if (s == null || s.trim().isEmpty()) {
it.remove(); // ✅ 安全
}
}替代方案:removeIf() 更简洁,但 Java 8+ 才有
Collection.removeIf(Predicate) 内部也是用 Iterator 实现的,语义清晰、代码短,适合单条件过滤。
参数差异:
– removeIf() 接收 Predicate<e></e>,返回 boolean 表示是否该删
– 不支持中途 break 或复杂逻辑(比如删第 3 个匹配项后停止)
性能影响:
– 和手写 Iterator 循环基本一致,没有额外开销
– 但注意:它不是 lazy 的,会遍历全部元素
list.removeIf(s -> s == null || s.trim().isEmpty()); // ✅ 简洁等效
兼容性提醒:如果项目还在用 Java 7,这条路走不通,必须退回 Iterator 写法。
想反向遍历删除?用普通 for 循环从末尾开始
这是少数可以不用 Iterator 的安全方式——因为删掉末尾元素不会影响前面元素的索引。
适用场景:
– 已知要按索引删(比如删掉所有偶数下标元素)
– 或逻辑简单、不想引入 Iterator 变量
注意点:
– 必须从 list.size() - 1 开始,递减到 0
– 删完不用调整 i,因为前面的索引没变
for (int i = list.size() - 1; i >= 0; i--) {
if (list.get(i).length() > 10) {
list.remove(i); // ✅ 安全
}
}遍历中删元素这件事,表面看只是换种写法,实际卡点都在「谁在维护迭代状态」——Iterator 对象自己管,你插手就乱;removeIf() 把这层封装了,但得看 JDK 版本;反向 for 是靠索引特性硬扛,灵活但不够通用。最容易被忽略的是:哪怕用了 Iterator,漏掉 next() 就调 remove(),或者连删两次,照样崩。










