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

Java for 與 foreach 循環深度對比:性能、局限性與底層原理

     編輯:Java 綜合教學

核心結論先行

  • for 循環條件中的變量只求值一次(見文末字節碼分析)。
  • foreach 是 JDK 5 引入的語法糖,遍歷數組/集合性能優於手寫 for,但不能完全替代 for。
  • 任何 foreach 都能改寫為 for,反之不成立。
  • foreach 不是關鍵字,編譯器將其轉換為迭代器或索引訪問代碼。

一、foreach 語法與適用對象

for (元素類型T 變量名O : 循環對象) {
    // 操作 O
}

循環對象可為:數組、實現 Iterable 的集合(List、Set 等)。

二、常見使用示例

遍歷 List

List<String> list = Arrays.asList("A", "B", "C");
for (String s : list) {
    System.out.println(s);
}

三、關鍵局限性:遍歷中不可修改集合結構

foreach 僅能遍歷,無法在遍歷過程中增刪集合元素,否則拋 ConcurrentModificationException。for 循環配合索引可安全修改。

// 錯誤示例
for (String s : list) {
    if ("B".equals(s)) list.remove(s); // 拋異常
}

// 正確做法:使用 Iterator 或倒序 for 循環
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    if ("B".equals(it.next())) it.remove();
}

四、特殊陷阱:for 循環條件求值一次

看代碼預測輸出:

List<Integer> list = new ArrayList<>();
list.add(1); list.add(2); list.add(3);

for (int i = 0, size = list.size(); i < size; i++) {
    System.out.println(list.get(i));
    if (i == 1) list.remove(0); // 刪除第一個元素
}

輸出:1、2、3(只有 3 次循環)。
原因:size = list.size() 在循環開始前只計算一次(值為 3),循環中 list 縮短但 size 不變,導致索引越過實際大小。

五、字節碼層面揭秘

foreach 編譯後字節碼

編譯器將 foreach 編譯為:

  • 數組:基於索引的訪問(iaload 等指令)。
  • 集合:調用 iterator() 獲取迭代器,循環調用 hasNext()、next()。

這就是為什麼 foreach 不能修改集合結構——迭代器的 remove() 是唯一安全方式,而 foreach 隱藏了迭代器引用。

六、性能對比

場景推薦方式原因
數組遍歷for / foreach 均可foreach 編譯為索引訪問,無額外開銷
ArrayList 遍歷for (int i=0; i隨機訪問 O(1),避免迭代器對象創建
LinkedList 遍歷foreach / Iterator順序訪問,foreach 內部用迭代器避免 O(n²)
需修改結構Iterator / ListIteratorforeach 不支持,for 需小心索引同步

總結

foreach 是讀取遍歷的利器,代碼簡潔、語義清晰;但遇到修改集合、需索引、高性能數組隨機訪問時,傳統 for 或 Iterator 更合適。理解「條件求值一次」與「編譯為迭代器」兩大底層機制,能避開 90% 的循環陷阱。

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