ArrayList 是 Java 開發中使用率最高的集合,遍歷操作更是高頻動作。本文詳細解析四種主流遍歷方式的語法、適用場景、效能特徵與避坑指南,助你寫出高效、優雅的代碼。
import java.util.*;
public class ArrayListTraversal {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("luojiahui");
list.add("luojiafeng");
// 方式一:Iterator 顯式迭代器
System.out.println("=== 1. Iterator ===");
Iterator<String> it1 = list.iterator();
while (it1.hasNext()) {
System.out.println(it1.next());
}
// 方式二:for 迴圈 + Iterator(語法糖本質相同)
System.out.println("\n=== 2. for + Iterator ===");
for (Iterator<String> it2 = list.iterator(); it2.hasNext(); ) {
System.out.println(it2.next());
}
// 方式三:增強 for 迴圈(for-each)—— 最推薦日常使用
System.out.println("\n=== 3. for-each ===");
for (String s : list) {
System.out.println(s);
}
// 方式四:傳統索引 for 迴圈
System.out.println("\n=== 4. Index for ===");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
| 維度 | Iterator 顯式 | for + Iterator | for-each | 索引 for |
|---|---|---|---|---|
| 語法本質 | 顯式調用 hasNext/next | 語法糖,編譯後同方式一 | 語法糖,編譯後同方式一 | 直接調用 get(index) |
| 隨機存取 | 不支援 | 不支援 | 不支援 | 支援 O(1) |
| 遍歷中刪除 | 安全 (it.remove()) | 安全 | 拋 ConcurrentModificationException | 需倒序或調整索引 |
| 可讀性 | 一般 | 一般 | 最佳 | 較好 |
| 效能(ArrayList) | 基準 | 同基準 | 同基準 | 略快 (無迭代器對象、直接 get) |
| 效能(LinkedList) | O(n) 總計 | 同 | 同 | O(n²) 災難(每次 get 遍歷) |
| 適用集合 | 所有 Collection | 所有 Collection | 所有 Iterable | 僅 RandomAccess 實現 |
// ArrayList 實現了 RandomAccess
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
Collections.binarySearch、sort 等演算法會檢查此介面,若無則退化為迭代器模式。list instanceof RandomAccess。
// ✅ Iterator 安全刪除
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if ("delete".equals(it.next())) it.remove();
}
// ✅ 索引倒序刪除(避免索引錯位)
for (int i = list.size() - 1; i >= 0; i--) {
if ("delete".equals(list.get(i))) list.remove(i);
}
// ✅ Java 8+ removeIf(內部用 Iterator,最簡潔)
list.removeIf("delete"::equals);
// ❌ for-each 刪除 → ConcurrentModificationException
for (String s : list) { if ("del".equals(s)) list.remove(s); } // 爆炸
// 內部迭代,支援鏈式操作、並行流
list.stream().forEach(System.out::println);
// 並行遍歷(大數據量、無副作用操作)
list.parallelStream().forEach(expensiveOperation::apply);
注意: Stream 有額外對象創建開銷,簡單遍歷不如 for-each 效能;但複雜篩選/轉換/聚合場景極大提升可讀性。
Benchmark Mode Cnt Score Error Units
indexFor thrpt 5 125.3 ± 2.1 ops/ms
forEach thrpt 5 118.7 ± 1.8 ops/ms
iterator thrpt 5 115.2 ± 1.5 ops/ms
streamForEach thrpt 5 95.4 ± 2.3 ops/ms
結論: ArrayList 下索引 for 最快,但差異在納秒級;可讀性優先選 for-each,需刪除用 Iterator/removeIf,需索引用索引 for。
RandomAccess)。沒有完美的遍歷方式,只有最適合場景的選擇。記住三條鐵律:
掌握這些,你的集合遍歷代碼將兼具高效、安全、優雅。