首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java ArrayList 遍歷四大方式全解析與效能對比

     編輯:Java 相關知識

前言

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 + Iteratorfor-each索引 for
語法本質顯式調用 hasNext/next語法糖,編譯後同方式一語法糖,編譯後同方式一直接調用 get(index)
隨機存取不支援不支援不支援支援 O(1)
遍歷中刪除安全 (it.remove())安全拋 ConcurrentModificationException需倒序或調整索引
可讀性一般一般最佳較好
效能(ArrayList)基準同基準同基準略快 (無迭代器對象、直接 get)
效能(LinkedList)O(n) 總計同同O(n²) 災難(每次 get 遍歷)
適用集合所有 Collection所有 Collection所有 Iterable僅 RandomAccess 實現

關鍵知識點

1. RandomAccess 標記介面


// ArrayList 實現了 RandomAccess
public class ArrayList<E> extends AbstractList<E> 
    implements List<E>, RandomAccess, Cloneable, Serializable
  • 標記「支援快速隨機存取」。
  • Collections.binarySearch、sort 等演算法會檢查此介面,若無則退化為迭代器模式。
  • 判斷依據: list instanceof RandomAccess。

2. 遍歷中刪除的正確姿勢


// ✅ 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); } // 爆炸

3. Java 8+ Stream API 遍歷


// 內部迭代,支援鏈式操作、並行流
list.stream().forEach(System.out::println);
// 並行遍歷(大數據量、無副作用操作)
list.parallelStream().forEach(expensiveOperation::apply);

注意: Stream 有額外對象創建開銷,簡單遍歷不如 for-each 效能;但複雜篩選/轉換/聚合場景極大提升可讀性。

效能實測參考(百萬級數據,JMH 基準測試)


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。

最佳實踐決策樹

  1. 只讀遍歷、無索引需求 → for-each(首選)。
  2. 遍歷中需刪除 → Iterator + remove() 或 removeIf()。
  3. 需索引、或隨機存取 → 索引 for(確認 RandomAccess)。
  4. LinkedList 等非隨機存取集合 → for-each / Iterator,禁用索引 for。
  5. 複雜業務邏輯(篩選、映射、聚合) → Stream API。
  6. 極致效能熱點(經 Profiling 確認) → 索引 for + 局部變量緩存 size。

總結

沒有完美的遍歷方式,只有最適合場景的選擇。記住三條鐵律:

  1. 日常首選 for-each:代碼最乾淨,效能差距可忽略。
  2. 遍歷刪除用 Iterator/removeIf:語義正確、避免 CME。
  3. 拒絕在 LinkedList 用索引 for:O(n²) 效能殺手。

掌握這些,你的集合遍歷代碼將兼具高效、安全、優雅。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved