Java 5 引入增強 for 循環(for-each),大幅簡化陣列與集合遍歷語法。本文系統梳理傳統與增強寫法、編譯器語法糖原理、型別相容規則、常見陷阱與效能真相。
// 陣列遍歷
int[] integers = {1, 2, 3, 4};
for (int i = 0; i < integers.length; i++) {
System.out.println(integers[i]);
}
// Collection 遍歷(需 Iterator)
Collection<String> list = Arrays.asList("A", "B", "C");
for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
System.out.println(it.next());
}
// 語法:for (元素型別 變數 : 目標對象) { ... }
// 陣列示例
for (int i : integers) { System.out.println(i); }
// 編譯器轉換為傳統索引循環
for (int $i = 0; $i < integers.length; $i++) {
int i = integers[$i]; System.out.println(i);
}
// Collection 示例
for (String s : list) { System.out.println(s); }
// 編譯器轉換為 Iterator 循環
for (Iterator<String> $it = list.iterator(); $it.hasNext(); ) {
String s = $it.next(); System.out.println(s);
}
關鍵點:編譯期語法糖,無執行期效能損耗;$i、$it 為編譯器生成的不衝突變數名。
in 常用作變數名,如 System.in)。final 修飾,編譯期禁止重新賦值(但可修改物件內部狀態)。
for (final int i : integers) { i = 5; // 編譯錯誤 }
int 遍歷 int[])。Object 遍歷 String[])。Integer 遍歷 int[],byte 遍歷 Byte[])。Object[] 元素型別為 Object,即使實際存 String 也無法用 String 接收。
Collection<String> 可直接用 String 接收,編譯器插入隱式轉型,型別安全有保障。| 場景 | 增強 for | 傳統 for / Iterator |
|---|---|---|
| 單純遍歷讀取 | ✅ 首選 | 可用 |
| 需要索引/位置 | ❌ 無索引 | ✅ |
| 遍歷中刪除元素 | ❌ 拋 ConcurrentModificationException | ✅ Iterator.remove() |
| 修改陣列/集合結構 | ❌ | ✅ |
| 多重循環嵌套需外層索引 | ❌ | ✅ |
for-each 結構最早見於 1979 年 Bourne Shell(for var in list; do ... done),Java 5 借鑑並適配自身型別系統。
善用增強 for 循環簡化代碼,關鍵時刻退回傳統寫法掌控細節,是 Java 開發者的基本功。