National Yunlin University of Science and Technology
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try a Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

1

Local AI

--

Uedu Code

--

雲林科技大學 AQI 56 27°C PM2.5 10
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 04

條件判斷

if/else、巢狀判斷、switch 與 switch 運算式
Interaction實作 20 minute(s)

Learning Objectives

  • 用 if、if-else、else if 依條件選擇要執行的程式,並寫出巢狀判斷
  • 說明 Java 的條件必須是 boolean,安排 else if 條件的先後順序
  • 避開省略大括號與用 == 比較字串這兩個常見陷阱
  • 寫出傳統 switch,說明 break 與 fall-through 的作用
  • 用箭頭 switch 與 switch 運算式(含 yield)依值選出結果

讓程式做選擇

到目前為止,程式都是由上往下一行一行全部執行。但真實的問題常常要依情況做不同的事:分數及格就印「通過」,否則印「補考」; 會員打折、非會員原價;輸入 1 是查詢、輸入 2 是存款。

條件判斷讓程式依據一個 boolean 的結果,選擇要執行哪一段程式碼。Java 有兩種寫法:

  • if/else:條件可以是任何 boolean 運算式,最有彈性
  • switch:拿一個值和好幾個固定的選項比對,選項很多時比一長串 else if 好讀

本課的動畫會清楚標出哪些行被執行、哪些行被跳過,注意看執行的箭頭怎麼跳。

if 與 if-else

if (條件) {
    // 條件是 true 時執行
}

if (條件) {
    // 條件是 true 時執行
} else {
    // 條件是 false 時執行
}
  • 條件寫在小括號裡,結果必須是 boolean。Java 不會把數字當成真假:int x = 5; if (x) { … } 會編譯錯誤 incompatible types: int cannot be converted to boolean,要寫成 if (x != 0)。這點和 Python、C 都不同
  • 不小心把 == 寫成 =:if (x = 5) 一樣會編譯錯誤,因為 x = 5 的結果是 int。Java 的嚴格在這裡幫你抓到了一個常見的錯誤
  • 大括號裡的程式碼形成一個區塊(block);在區塊裡宣告的變數,離開區塊就不能再使用

if 的區塊裡可以再寫 if,叫做巢狀 if(nested if):先判斷外層的條件,成立了才進去判斷內層的條件。

if、if-else 與巢狀 if

第 8 行的條件不成立,箭頭直接跳過大括號裡的程式;第 13 行的 if-else 只會執行其中一邊。第 21 行開始是巢狀 if:外層成立之後,才會判斷內層的 amount >= 1000。

else if 串

三種以上的情況,用 else if 串起來:

if (score >= 90) {
    grade = "A";
} else if (score >= 80) {
    grade = "B";
} else if (score >= 70) {
    grade = "C";
} else {
    grade = "F";
}

Java 由上往下檢查,第一個成立的條件執行它的區塊,其餘的全部跳過;全部都不成立才執行最後的 else(else 可以省略)。

所以條件的順序很重要:85 分同時符合 score >= 80 和 score >= 60,誰寫在前面就由誰決定。 範圍有重疊時,要把範圍小(條件嚴格)的放前面。另外,因為走到 else if (score >= 80) 時已經確定 score 小於 90, 不需要再寫成 score >= 80 && score < 90。

上面的 grade 沒有初始值也能編譯,因為每一條路(包含最後的 else)都有指派;如果拿掉 else, javac 會認為 grade 可能沒有被指派,使用它時報錯 variable grade might not have been initialized。

成績等第與條件順序

上半段 85 分:第 6 行不成立、第 8 行成立,之後的 else if 一個都不會檢查。下半段把 score >= 60 放在最前面,85 分在第一個條件就成立,得到錯誤的 D。

想一想:if 與 else if

1.

下面的程式執行結果是?

public class Main {
    public static void main(String[] args) {
        int count = 3;
        if (count) {
            System.out.println("有資料");
        }
    }
}
2.

下面的程式會印出什麼?

public class Main {
    public static void main(String[] args) {
        int t = 25;
        if (t > 10) {
            System.out.println("溫暖");
        } else if (t > 20) {
            System.out.println("炎熱");
        } else {
            System.out.println("寒冷");
        }
        if (t > 20) {
            System.out.println("開冷氣");
        }
    }
}
3.

下面的程式會印出什麼?

public class Main {
    public static void main(String[] args) {
        int a = 5;
        if (a > 10)
            System.out.println("X");
            System.out.println("Y");
        System.out.println("Z");
    }
}
第 1 次作答

兩個常見陷阱

陷阱一:省略大括號。 if 後面只有一個敘述時,Java 允許省略大括號,但這時 if 只管下一個敘述:

if (stock > 0)
    System.out.println("有貨");
    System.out.println("可以下單");   // 縮排看起來在 if 裡,其實一定會執行

Java 不看縮排。之後要在 if 裡多加一行時,很容易忘了補上大括號,所以一律寫大括號是比較安全的習慣。

陷阱二:用 == 比較字串。 String 是參照型別,== 比較的是「是不是同一個字串物件」,不是內容(第 08 課會說明參照)。 從鍵盤讀入、或程式算出來的字串,內容即使一樣,也可能是不同的物件,== 就會是 false。比較內容一律用 equals:

if (cmd.equals("quit")) { … }              // 內容完全相同
if (cmd.equalsIgnoreCase("QUIT")) { … }    // 忽略大小寫

基本型別(int、char、boolean 等)比較值時用 == 沒有問題。

大括號與字串比較

第 7 行的條件不成立,只有第 8 行被跳過,第 9 行照樣執行。後半段讀入使用者輸入的 quit,內容和 "quit" 一模一樣,== 卻是 false。

傳統 switch

拿一個值和好幾個固定的選項比對時,可以用 switch:

switch (day) {
    case 1:
        System.out.println("星期一");
        break;
    case 2:
        System.out.println("星期二");
        break;
    default:
        System.out.println("其他");
}
  • 小括號裡的值可以是 int、char、String、enum 等型別(不能是 double、boolean、long);每個 case 後面是一個常數
  • Java 跳到相符的 case,從那裡開始一路往下執行,直到遇見 break 或 switch 結束。忘了寫 break,就會繼續執行下一個 case 的程式, 叫做 fall-through(穿透)。這常常是錯誤來源,但也可以刻意利用:好幾個 case 共用同一段程式時,把它們疊在一起
  • 沒有任何 case 相符時執行 default;default 可以省略

break 與 fall-through

day 是 3,跳到 case 3。這個 case 沒有 break,所以會繼續執行 case 4 的程式,一直到第 16 行的 break 才離開。下半段的 case 4: case 6: case 9: case 11: 疊在一起,四個月份共用同一段程式。

箭頭 switch 與 switch 運算式

Java 14 起,switch 有了新的寫法:

箭頭 switch:用 case 值 -> 代替 case 值:,執行完箭頭右邊的程式就結束,不會穿透,也不必寫 break。 好幾個值共用同一段程式時,用逗號列出:case "latte", "mocha" ->。

switch (drink) {
    case "americano" -> System.out.println("美式咖啡");
    case "latte", "mocha" -> System.out.println("加牛奶的咖啡");
    default -> System.out.println("其他飲料");
}

switch 運算式:switch 本身可以算出一個值,直接指派給變數(注意最後的分號):

String season = switch (month) {
    case 3, 4, 5 -> "春季";
    case 6, 7, 8 -> "夏季";
    case 9, 10, 11 -> "秋季";
    default -> "冬季";
};
  • switch 運算式必須涵蓋所有可能的值,所以通常要有 default;少了 default,javac 會回報 the switch expression does not cover all possible input values
  • 箭頭右邊需要好幾行時,寫成區塊 { … },用 yield 交出這個 case 的值(yield 是給 switch 運算式用的,不是 return)

新寫的程式建議優先使用箭頭寫法,可以避開忘了 break 的錯誤。

箭頭 switch 與 yield

第一段只執行 "latte", "mocha" 那一個 case,執行完直接離開。第二、三段的 switch 是運算式,結果存進 season 與 price;第 26 行用 yield 交出區塊算出的值。

想一想:字串比較與 switch

1.

下面的程式會印出什麼?

public class Main {
    public static void main(String[] args) {
        String s1 = "Java";
        String s2 = new String("Java");
        System.out.println((s1 == s2) + " " + s1.equals(s2));
    }
}
2.

下面的程式會印出什麼?

public class Main {
    public static void main(String[] args) {
        int n = 1;
        switch (n) {
            case 1:
                System.out.print("A");
            case 2:
                System.out.print("B");
                break;
            case 3:
                System.out.print("C");
            default:
                System.out.print("D");
        }
        System.out.println();
    }
}
3.

下面的程式會印出什麼?

public class Main {
    public static void main(String[] args) {
        char op = '*';
        int r = switch (op) {
            case '+' -> 6 + 3;
            case '-' -> 6 - 3;
            case '*' -> {
                int t = 6 * 3;
                yield t + 1;
            }
            default -> 0;
        };
        System.out.println(r);
    }
}
第 1 次作答

動手寫:月份與季節

讀入一個月份。月份不在 1~12 之間時印出「月份不正確」;否則用 switch 運算式 算出季節(3~5 月春季、6~8 月夏季、9~11 月秋季、其餘冬季)。這次的輸入是 8。寫完可以把輸入改成 13、1 再試試看。

你的輸出
預期輸出

重點回顧

  • if (條件) { … } else { … }:條件必須是 boolean,if (x)、if (x = 5) 都無法編譯
  • else if 串由上往下檢查,只執行第一個成立的區塊;範圍重疊時把嚴格的條件放前面
  • 巢狀 if:外層成立才判斷內層
  • 省略大括號時 if 只管下一個敘述,Java 不看縮排,所以一律寫大括號
  • 字串比較內容用 equals(不分大小寫用 equalsIgnoreCase),== 比的是不是同一個物件
  • 傳統 switch 從相符的 case 一路往下執行到 break(fall-through);沒有相符時執行 default
  • 箭頭 switch(case 值 ->)不會穿透;switch 運算式直接算出一個值,必須涵蓋所有情況,區塊裡用 yield 交出結果(Java 14 起)
這一課完成了!
Next lesson:迴圈
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。