for 循環三大語法形態
1. 傳統 for 循環 (索引控制)
for (int i = 0; i < arr.length; i++) {
// 可控制步長、方向、中斷
System.out.println(arr[i]);
}
// 逆序遍歷
for (int i = list.size() - 1; i >= 0; i--) {
// 安全刪除元素
if (shouldRemove(list.get(i))) list.remove(i);
}
2. 增強 for 循環 (for-each, Java 5+)
// 數組
int[] nums = {1, 2, 3};
for (int n : nums) System.out.println(n);
// 集合 (實現 Iterable)
List list = Arrays.asList("a", "b", "c");
for (String s : list) System.out.println(s);
// 多維數組
int[][] matrix = {{1,2}, {3,4}};
for (int[] row : matrix) {
for (int cell : row) System.out.print(cell + " ");
}
| 優點 | 缺點/限制 |
| 語法簡潔,無索引越界風險 | 無法獲取索引位置 |
編譯器優化,性能接近傳統 for | 不能在遍歷時刪除集合元素 (需 Iterator) |
適用於只讀遍歷 | 不能修改數組/集合結構 (如替換元素需索引) |
3. Stream API 函數式遍歷 (Java 8+)
// 基礎遍歷
list.forEach(System.out::println);
// 並行處理大數據量
list.parallelStream().forEach(expensiveOperation);
// 配合過濾、轉換
List result = list.stream()
.filter(s -> s.length() > 3)
.map(String::toUpperCase)
.collect(Collectors.toList());
嵌套循環與標簽控制
// 標簽跳出多層循環
outer:
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (matrix[i][j] == target) {
System.out.println("Found at " + i + "," + j);
break outer; // 直接跳出外層
}
}
}
// continue 標簽跳過外層當前迭代
outer:
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (skipCondition) continue outer; // 跳過該行剩餘列
}
}
經典算法模式
1. 累加求和 / 計數器
// 1 到 100 求和
int sum = 0;
for (int i = 1; i <= 100; i++) sum += i;
// 或 Gauss 公式: n*(n+1)/2
// 統計符合條件元素
long count = 0;
for (Item item : items) {
if (item.isValid()) count++;
}
2. 階乘 / 累乘 (雙層循環)
int limit = 10;
for (int i = 1; i <= limit; i++) {
long factorial = 1;
for (int factor = 2; factor <= i; factor++) {
factorial *= factor;
}
System.out.println(i + "! = " + factorial);
}
3. 雙指針 / 滑動窗口
// 有序數組雙指針查找目標和
int left = 0, right = nums.length - 1;
while (left < right) {
int sum = nums[left] + nums[right];
if (sum == target) return new int[]{left, right};
else if (sum < target) left++;
else right--;
}
性能優化實戰
1. 循環不變量外提
// 低效:每次迭代重複計算
for (int i = 0; i < list.size(); i++) {
process(list.get(i), expensiveComputation());
}
// 高效:提取不變量
int size = list.size();
Result cached = expensiveComputation();
for (int i = 0; i < size; i++) {
process(list.get(i), cached);
}
2. 數組優於集合 (熱點路徑)
// 熱點循環:優先用數組避免 Iterator 分配
int[] arr = list.stream().mapToInt(Integer::intValue).toArray();
for (int i = 0, len = arr.length; i < len; i++) {
// 直接索引訪問,JIT 易優化為向量化指令
}
3. 避免自動裝箱/拆箱
// 低效:List 產生大量 Integer 對象
List list = new ArrayList<>();
for (int i = 0; i < 1_000_000; i++) list.add(i);
long sum = 0;
for (Integer n : list) sum += n; // 拆箱
// 高效:原始類型數組或專用集合
int[] arr = new int[1_000_000];
for (int i = 0; i < arr.length; i++) arr[i] = i;
long sum = 0;
for (int n : arr) sum += n; // 無裝箱
常見錯誤與避坑
| 錯誤類型 | 錯誤代碼 | 後果 | 修正 |
| 索引越界 | for (int i=0; i<=arr.length; i++) | ArrayIndexOutOfBoundsException | i < arr.length |
| 增強 for 中刪除 | for (String s: list) if(...) list.remove(s) | ConcurrentModificationException | 用 Iterator.remove() 或反向索引刪除 |
| 修改循環變量 | for (int i=0; i<10; i++) { i = 5; } | 死循環或邏輯錯誤 | 勿修改循環變量 |
| 浮點數作循環條件 | for (double d=0; d!=1.0; d+=0.1) | 精度誤差導致不終止 | 用整數計數或 BigDecimal |
| 空集合 NullPointer | for (Item i : nullList) | NPE | 先判空或用 Collections.emptyList() |
最佳實踐清單
- 只讀遍歷集合/數組 → 增強 for (最簡潔)
- 需要索引/逆序/刪除 → 傳統 for
- 複雜數據流轉換 → Stream API (可讀性優)
- 極致性能熱點 → 原始類型數組 + 傳統 for + 循環不變量外提
- 並行處理大數據 → parallelStream 或 分治 + ForkJoinPool
- 嵌套循環需跳出 → 標簽 break/continue