推荐根据场景选择遍历方式:单线程用增强for或普通for;边遍历边删除必须用迭代器remove();多线程需线程安全容器或同步。普通for索引遍历高效可控,适合随机访问。

在 Java 中对 ArrayList 进行安全且高效的遍历,关键在于避开并发修改异常(ConcurrentModificationException)和避免不必要的性能开销。最推荐的方式是根据使用场景选择合适的遍历方式:单线程下优先用增强 for 循环或普通 for 索引遍历;需要边遍历边删除时,必须用迭代器的 remove() 方法;多线程环境下则需考虑线程安全容器或同步机制。
普通 for 循环(索引遍历)——高效、可控、适合随机访问
ArrayList 底层是数组,支持 O(1) 随机访问,所以用传统 for (int i = 0; i 方式效率最高,尤其适合只读或需索引的场景。注意不要在循环中反复调用 <code>list.size()(虽然 JIT 通常会优化),更稳妥写法是提前缓存长度:
-
✅ 推荐写法:
for (int i = 0, size = list.size(); i -
❌ 避免写法:
for (int i = 0; i (每次迭代都调用方法,语义清晰但略冗余) - 可安全用于修改元素(如
list.set(i, newValue)),但不能直接remove(i)或add(...),否则会引发索引错乱或跳过元素
增强 for 循环(for-each)——简洁安全,仅限只读或不可变操作
语法简洁:for (String s : list) { ... },本质是通过迭代器实现。它天然防止在遍历中意外调用 list.remove() 导致的并发修改异常(因为会立刻报错),属于“ Fail-fast ”机制,是一种安全提示。
- ✅ 适用场景:纯遍历、只读访问、打印、计算聚合值(sum、max 等)
-
❌ 禁止操作:循环体内调用
list.remove()或list.add(),会抛ConcurrentModificationException - 不能获取当前索引,也不支持反向遍历
迭代器遍历(Iterator)——唯一安全删除/修改的遍历方式
当需要在遍历过程中动态删除符合条件的元素时,必须使用 Iterator 并调用其 remove() 方法。这是 JDK 明确保证线程安全(单线程下)的唯一方式:
-
✅ 正确删除:
Iterator<string> it = list.iterator(); while (it.hasNext()) { String s = it.next(); if (s.isEmpty()) it.remove(); }</string> -
❌ 错误删除:
for (String s : list) { if (s.isEmpty()) list.remove(s); }→ 必抛异常 -
Iterator不支持添加元素(add()方法未实现),如需插入,应改用ListIterator(支持双向遍历与增删)
多线程环境下的遍历——避免竞态,选对容器
普通 ArrayList 不是线程安全的。若多个线程同时读写,即使只读+一个写线程,也可能因扩容导致数据不一致或异常。
-
✅ 安全方案一:用
Collections.synchronizedList(new ArrayList()),但遍历仍需手动同步:synchronized(list) { for (E e : list) { ... } } -
✅ 安全方案二(推荐):改用
CopyOnWriteArrayList,适合读多写少场景。它的迭代器基于快照,遍历时即使原列表被修改也不会抛异常,但注意——迭代器无法反映遍历期间的新增/删除 -
❌ 避免:在无同步保护下让多个线程直接共享并遍历原始
ArrayList
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











