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

Java 流程控制核心:條件判斷、迴圈與分支語句深度解析

     編輯:Java 程式設計入門

前言:掌握程式執行流向的關鍵

程式的靈魂在於流程控制。無論多麼複雜的演算法、商務邏輯、遊戲規則,最終都由三種基本結構組合而成:順序、選擇、迴圈。本章將系統解析 Java 的流程控制語句,從基礎語法到進階技巧、常見陷阱與最佳實踐,幫你建立堅實的邏輯思維基礎。

7.1 選擇結構:if-else 條件判斷

基本 if 語句


int score = 85;
if (score >= 60) {
    System.out.println("及格");
}
// 輸出: 及格

關鍵點:條件必須是 boolean 型別;單行敘述可省略大括號,但強烈建議永遠加上大括號,避免維護時誤判歸屬。

if-else 雙向分支


int score = 45;
if (score >= 60) {
    System.out.println("及格");
} else {
    System.out.println("不及格");
}
// 輸出: 不及格

if-else if-else 多重條件


int score = 82;
if (score >= 90) {
    System.out.println("優等 (A)");
} else if (score >= 80) {
    System.out.println("甲等 (B)");
} else if (score >= 70) {
    System.out.println("乙等 (C)");
} else if (score >= 60) {
    System.out.println("丙等 (D)");
} else {
    System.out.println("不及格 (F)");
}
// 輸出: 甲等 (B)

執行機制:由上而下評估,第一個符合條件的區塊執行後即跳出,不再檢查後續條件。因此條件順序至關重要(通常由嚴格到寬鬆)。

巢狀 if 與邏輯運算子


// 巢狀 if
if (user.isLoggedIn()) {
    if (user.hasPermission("ADMIN")) {
        showAdminPanel();
    } else {
        showUserPanel();
    }
} else {
    showLoginPage();
}

// 扁平化:使用邏輯運算子
if (user.isLoggedIn() && user.hasPermission("ADMIN")) {
    showAdminPanel();
} else if (user.isLoggedIn()) {
    showUserPanel();
} else {
    showLoginPage();
}

常見錯誤:分號陷阱


// 錯誤!if 後加分號,導致區塊脫離條件控制
if (score >= 60); {  // ← 這個分號等同於空敘述
    System.out.println("及格"); // 無條件執行!
}

// 正確
if (score >= 60) {
    System.out.println("及格");
}

三元運算子:簡潔的條件表達式


int score = 75;
String result = (score >= 60) ? "及格" : "不及格";
// 等同於:
// String result;
// if (score >= 60) result = "及格"; else result = "不及格";

System.out.println(result); // 輸出: 及格

// 巢狀三元 (不建議,降低可讀性)
String grade = score >= 90 ? "A" : score >= 80 ? "B" : score >= 70 ? "C" : "F";

7.2 迴圈結構:重複執行的藝術

while 迴圈:不定次數、先判斷後執行


// 經典累加:1 + 2 + ... + 100
int sum = 0;
int i = 1;
while (i <= 100) {
    sum += i;
    i++;
}
System.out.println("總和: " + sum); // 5050

// 讀取輸入直到 sentinel 值
Scanner sc = new Scanner(System.in);
int num;
while ((num = sc.nextInt()) != -1) { // -1 為結束標記
    process(num);
}

do-while 迴圈:至少執行一次、後判斷


// 選單驅動程式:至少顯示一次選單
int choice;
do {
    showMenu();
    choice = sc.nextInt();
    handleChoice(choice);
} while (choice != 0); // 0 為離開

for 迴圈:定次數、結構化控制


// 標準形式
for (int i = 1; i <= 10; i++) {
    System.out.print(i + " "); // 1 2 3 ... 10
}

// 多重初始化/更新
for (int i = 0, j = 10; i < j; i++, j--) {
    System.out.println("i=" + i + ", j=" + j);
}

// 增強型 for (for-each):遍歷陣列/集合 (Java 5+)
int[] numbers = {3, 1, 4, 1, 5, 9};
for (int n : numbers) {
    System.out.print(n + " ");
}

// 字串遍歷
for (char c : "Java".toCharArray()) {
    System.out.print(c + "-"); // J-a-v-a-
}

三種迴圈對比與選擇指南

迴圈類型適用場景關鍵特性
for已知迴圈次數、陣列索引存取、計數器邏輯初始化、條件、更新集中管理
while未知次數、依條件持續、串流讀取先判斷,可能零次執行
do-while選單、輸入驗證、至少執行一次後判斷,保證最少一次
for-each遍歷集合/陣列、不需索引語法簡潔、避免索引越界、不可修改集合結構

迴圈控制語句:break 與 continue


// break:立即跳出迴圈
for (int i = 1; i <= 100; i++) {
    if (i == 50) break;
    System.out.print(i + " "); // 只輸出 1~49
}

// continue:跳過本次迭代,直接進入下一次判斷
for (int i = 1; i <= 10; i++) {
    if (i % 2 == 0) continue; // 跳過偶數
    System.out.print(i + " "); // 1 3 5 7 9
}

// 標籤 break/continue:跳出多層巢狀迴圈
outer: for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        if (i == 1 && j == 1) break outer; // 直接跳出外層
        System.out.println("i=" + i + ", j=" + j);
    }
}

無窮迴圈與防禦性寫法


// 故意無窮迴圈 (需內部 break)
while (true) {
    String input = readCommand();
    if ("exit".equals(input)) break;
    process(input);
}

// 防禦性:避免死循環
int maxIterations = 10000;
int count = 0;
while (condition && count++ < maxIterations) {
    // 處理邏輯
}
if (count >= maxIterations) log.warn("迴圈超過最大次數,可能發生死循環");

7.3 多分支結構:switch-case 模式匹配

傳統 switch (Java 11 前)


int day = 3;
String dayName;
switch (day) {
    case 1: dayName = "星期一"; break;
    case 2: dayName = "星期二"; break;
    case 3: dayName = "星期三"; break;
    case 4: dayName = "星期四"; break;
    case 5: dayName = "星期五"; break;
    case 6: dayName = "星期六"; break;
    case 7: dayName = "星期日"; break;
    default: dayName = "無效日期"; break;
}
System.out.println(dayName); // 星期三

關鍵規則:

  • case 常數必須為 int、char、String (Java 7+)、enum (Java 5+)
  • fall-through 特性:缺少 break 會繼續執行下一個 case(有時可利用此特性合併 case)
  • default 為可選,建議保留處理預期外數值

現代 Switch Expressions (Java 12+ Preview → Java 14 標準)


// 箭頭語法:無 fall-through、可作為表達式回傳值
String dayName = switch (day) {
    case 1 -> "星期一";
    case 2 -> "星期二";
    case 3 -> "星期三";
    case 4 -> "星期四";
    case 5 -> "星期五";
    case 6, 7 -> "週末"; // 多值合併
    default -> "無效日期";
};

// 區塊語法:複雜邏輯、需用 yield 回傳
int dayType = switch (day) {
    case 1, 2, 3, 4, 5 -> {
        System.out.println("平日");
        yield 1; // 工作日
    }
    case 6, 7 -> {
        System.out.println("假日");
        yield 2; // 休息日
    }
    default -> {
        System.out.println("錯誤");
        yield -1;
    }
};

Pattern Matching for switch (Java 17+ Preview → Java 21 標準)


// 型別模式匹配
Object obj = "Hello";
String desc = switch (obj) {
    case Integer i -> "整數: " + i;
    case String s -> "字串長度: " + s.length();
    case Double d -> "浮點數: " + d;
    case null -> "空值";
    default -> "其他型別: " + obj.getClass().getSimpleName();
};

// 守衛條件 (when)
int num = 15;
String category = switch (num) {
    case int n when n < 0 -> "負數";
    case int n when n == 0 -> "零";
    case int n when n % 2 == 0 -> "正偶數";
    case int n -> "正奇數"; // 預設匹配剩餘 int
    default -> "非整數";
};

Enum 與 Switch 完美搭配


enum OrderStatus { PENDING, PAID, SHIPPED, DELIVERED, CANCELLED }

OrderStatus status = OrderStatus.PAID;
String message = switch (status) {
    case PENDING -> "訂單待付款";
    case PAID -> "付款成功,備貨中";
    case SHIPPED -> "已出貨,追蹤號: " + generateTrackingNo();
    case DELIVERED -> "已送達,請確認收貨";
    case CANCELLED -> "訂單已取消";
    // 無需 default,編譯器會檢查是否涵蓋所有 enum 值
};

7.4 進階流程控制技巧

try-with-resources 自動資源管理 (Java 7+)


// 傳統寫法:需手動 close,易漏寫
FileReader fr = null;
try {
    fr = new FileReader("data.txt");
    // 讀取...
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (fr != null) try { fr.close(); } catch (IOException ignore) {}
}

// 現代寫法:自動關閉,實作 AutoCloseable 介面即可
try (FileReader fr = new FileReader("data.txt");
     BufferedReader br = new BufferedReader(fr)) {
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    e.printStackTrace();
}

Objects.requireNonNull 與驗證輔助


public void setName(String name) {
    this.name = Objects.requireNonNull(name, "名稱不可為空");
    // 等同於:
    // if (name == null) throw new NullPointerException("名稱不可為空");
}

public void setAge(int age) {
    if (age < 0 || age > 150) 
        throw new IllegalArgumentException("年齡必須在 0-150 之間: " + age);
    this.age = age;
}

Stream API 函數式流程控制 (Java 8+)


List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

// 篩選、轉換、收集
List evenSquares = numbers.stream()
    .filter(n -> n % 2 == 0)      // 篩選偶數
    .map(n -> n * n)              // 平方
    .collect(Collectors.toList()); // [4, 16, 36, 64, 100]

// 短路操作:找第一個符合條件
Optional firstBig = numbers.stream()
    .filter(n -> n > 5)
    .findFirst(); // Optional[6]

// 條件判斷
boolean anyMatch = numbers.stream().anyMatch(n -> n > 100); // false
boolean allMatch = numbers.stream().allMatch(n -> n > 0);   // true

7.5 實戰演練:經典算法題

練習 1:質數判斷 (試除法優化)


public boolean isPrime(int n) {
    if (n <= 1) return false;
    if (n <= 3) return true;      // 2, 3 是質數
    if (n % 2 == 0 || n % 3 == 0) return false; // 排除 2, 3 的倍數
    
    // 只需檢查到 sqrt(n),且跳過 6 的倍數附近
    for (int i = 5; i * i <= n; i += 6) {
        if (n % i == 0 || n % (i + 2) == 0) return false;
    }
    return true;
}

// 測試
for (int i = 1; i <= 50; i++) {
    if (isPrime(i)) System.out.print(i + " "); // 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
}

練習 2:九九乘法表 (巢狀迴圈格式化輸出)


for (int i = 1; i <= 9; i++) {
    for (int j = 1; j <= i; j++) { // 下三角
        System.out.printf("%dx%d=%-2d ", j, i, i*j);
    }
    System.out.println();
}
/*
1x1=1  
1x2=2  2x2=4  
1x3=3  2x3=6  3x3=9  
...
*/

練習 3:猜數字遊戲 (do-while + Random)


import java.util.*;

public class GuessNumberGame {
    public static void main(String[] args) {
        Random rand = new Random();
        int answer = rand.nextInt(100) + 1; // 1-100
        Scanner sc = new Scanner(System.in);
        int guess, count = 0;
        
        System.out.println("=== 猜數字遊戲 (1-100) ===");
        do {
            System.out.print("請輸入猜測: ");
            guess = sc.nextInt();
            count++;
            
            if (guess > answer) System.out.println("太大了!");
            else if (guess < answer) System.out.println("太小了!");
            else System.out.printf("恭喜!答案是 %d,共猜了 %d 次%n", answer, count);
        } while (guess != answer);
    }
}

練習 4:費波納契數列 (迴圈 vs 遞迴)


// 迴圈版:O(n) 時間、O(1) 空間
public long fibIterative(int n) {
    if (n <= 1) return n;
    long a = 0, b = 1;
    for (int i = 2; i <= n; i++) {
        long c = a + b;
        a = b;
        b = c;
    }
    return b;
}

// 遞迴版:O(2^n) 指數時間、O(n) 堆疊空間 (教學用,實務避免)
public long fibRecursive(int n) {
    if (n <= 1) return n;
    return fibRecursive(n-1) + fibRecursive(n-2);
}

// 記憶化遞迴:O(n) 時間
Map memo = new HashMap<>();
public long fibMemo(int n) {
    if (n <= 1) return n;
    return memo.computeIfAbsent(n, k -> fibMemo(k-1) + fibMemo(k-2));
}

7.6 除錯與最佳實踐清單

常見邏輯錯誤

錯誤類型錯誤程式碼正確寫法
浮點數比較if (x == 0.1 + 0.2)if (Math.abs(x - 0.3) < 1e-9)
字串比較if (str == "hello")if ("hello".equals(str))
迴圈邊界for (int i=0; i<=arr.length; i++)for (int i=0; i
修改集合for (String s: list) if (cond) list.remove(s);list.removeIf(cond); 或 Iterator
switch 漏 breakcase 1: ... case 2: ...加上 break 或用 switch expression

程式碼品質指南

  1. 單一職責:每個方法只做一件事,超過 20 行考慮拆分
  2. 守衛條款:參數驗證提前返回,減少巢狀縮排
  3. 避免深層巢狀:超過 3 層 if/for 考慮重構
  4. 有意義命名:isUserValid 勝過 check(),MAX_RETRY 勝過 3
  5. 單元測試:邊界值 (0, 1, max, null, empty) 必測

效能考量

  • 熱點路徑避免物件分配 (如迴圈內 new String())
  • 大量字串拼接用 StringBuilder
  • 集合預估大小 new ArrayList<>(expectedSize)
  • 優先使用基本型別 int 而非包裝型別 Integer

流程控制是程式設計的骨架。熟練掌握 if-else、switch、for/while/do-while、break/continue、try-with-resources 等語句,並理解現代 Java (switch expression、pattern matching、Stream API) 的演進,能讓你寫出更清晰、健壯、高效的程式碼。建議配合 LeetCode、HackerRank 等平台大量練習,將語法內化為直覺邏輯。

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