for-each循环遍历ArrayList最安全,因其底层使用Iterator、语法简洁且自动避免索引越界和ConcurrentModificationException(前提是遍历时不修改集合);但删改操作、Stream惰性求值及混用Iterator.remove()与list.remove()易引发问题。

用 for-each 循环遍历 ArrayList 最安全
绝大多数情况下,直接用 for-each 是首选。它底层调用 Iterator,语法简洁,且自动规避了手动管理索引和并发修改异常(ConcurrentModificationException)的风险——前提是遍历时不修改集合本身。
常见错误现象:有人写 for (int i = 0; i 然后在循环体里调用 list.remove(i),结果漏删、越界或抛出异常。
实操建议:
- 只读遍历 → 无脑用
for (String s : list) - 需要索引 → 改用传统
for循环,但避免在循环中增删元素 - 要边遍历边删除 → 必须用
Iterator.remove(),不能用list.remove()
用 Iterator 遍历时删除元素的唯一正确方式
ArrayList 的 Iterator 是 fail-fast 的,一旦检测到结构被外部修改(比如调用 list.remove()),下一次调用 next() 或 hasNext() 就会抛 ConcurrentModificationException。但 Iterator.remove() 是特例,它是被允许的唯一安全删除方式。
立即学习“Java免费学习笔记(深入)”;
示例:
Iteratorit = list.iterator(); while (it.hasNext()) { String s = it.next(); if (s.startsWith("A")) { it.remove(); // ✅ 正确 } }
错误写法:
for (String s : list) {
if (s.startsWith("A")) {
list.remove(s); // ❌ 抛 ConcurrentModificationException
}
}
用 ListIterator 反向遍历或双向操作
当需要从后往前遍历,或在遍历中插入元素(不只是删除),ListIterator 比普通 Iterator 更合适。它支持 hasPrevious()、previous()、add() 和 set()。
注意点:
-
ListIterator只能用于List实现类(如ArrayList),不能用于Set或Map -
add()插入后,新元素会被后续的next()跳过,但会被previous()立即看到 - 创建时可指定起始索引:
list.listIterator(list.size())表示从末尾开始反向遍历
Stream API 遍历适合函数式过滤/映射场景
Java 8+ 引入的 stream() 不是传统“遍历”,而是声明式处理。它适合做过滤、转换、聚合,但不适合需要精确控制流程(如 break、continue)或依赖索引顺序副作用的操作。
性能影响:
- 小数据量(
- 大数据量 + 多次中间操作(如多次
filter)可能比传统循环稍慢,因有对象创建和函数调用开销 - 并行流(
parallelStream())仅在 CPU 密集型、无状态操作中才有收益,对 I/O 或含同步逻辑的场景反而更差
示例(只读 + 过滤):
list.stream()
.filter(s -> s.length() > 3)
.forEach(System.out::println);
遍历看似简单,但删改逻辑、fail-fast 机制、迭代器状态、Stream 的惰性求值这些细节,一不留神就踩坑。尤其在多线程或嵌套循环里,Iterator.remove() 和 list.remove() 的混用是最常被忽略的陷阱。










