Java Switch Expression (Java 14+)

Java 14 引入了 Switch Expression(切換表達式),這是一種更簡潔、更現代化的 switch 語法。與傳統的 switch 敘述不同,Switch Expression 可以回傳值,並且使用箭頭語法 (->) 讓程式碼更清晰。

傳統 switch vs Switch Expression

傳統 switch 敘述

String dayType;
int day = 3;

switch (day) {
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
        dayType = "工作日";
        break;
    case 6:
    case 7:
        dayType = "假日";
        break;
    default:
        dayType = "未知";
}
System.out.println(dayType);  // 工作日

Switch Expression(箭頭語法)

int day = 3;

String dayType = switch (day) {
    case 1, 2, 3, 4, 5 -> "工作日";
    case 6, 7 -> "假日";
    default -> "未知";
};

System.out.println(dayType);  // 工作日

Switch Expression 的優勢:

  • 可以直接回傳值並賦予變數
  • 多個 case 可以用逗號合併
  • 不需要 break,避免 fall-through 錯誤
  • 程式碼更簡潔易讀

箭頭語法 (->)

箭頭語法是 Switch Expression 的核心特色:

int month = 8;

String season = switch (month) {
    case 3, 4, 5 -> "春天";
    case 6, 7, 8 -> "夏天";
    case 9, 10, 11 -> "秋天";
    case 12, 1, 2 -> "冬天";
    default -> "無效月份";
};

System.out.println(season);  // 夏天

多行程式碼區塊與 yield

當 case 需要執行多行程式碼時,使用大括號 {} 包裹,並用 yield 關鍵字回傳值:

int score = 85;

String grade = switch (score / 10) {
    case 10, 9 -> "A";
    case 8 -> {
        System.out.println("成績不錯!");
        yield "B";
    }
    case 7 -> "C";
    case 6 -> "D";
    default -> {
        System.out.println("需要加油!");
        yield "F";
    }
};

System.out.println("等級: " + grade);
// 成績不錯!
// 等級: B

yield 是 Java 14 新增的關鍵字,專門用於 Switch Expression 中回傳值。

冒號語法搭配 yield

Switch Expression 也可以使用傳統的冒號語法 (:),但需要用 yield 回傳值:

int day = 3;

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

System.out.println(dayName);  // 星期三

注意:使用冒號語法時不能用 break,必須用 yield

完整性檢查(Exhaustiveness)

Switch Expression 要求必須處理所有可能的值。對於 enum 類型,編譯器會檢查是否涵蓋所有列舉值:

enum Color { RED, GREEN, BLUE }

Color color = Color.GREEN;

String colorName = switch (color) {
    case RED -> "紅色";
    case GREEN -> "綠色";
    case BLUE -> "藍色";
    // 不需要 default,因為已涵蓋所有 enum 值
};

System.out.println(colorName);  // 綠色

對於其他類型(如 intString),通常需要 default 分支:

int value = 5;

String result = switch (value) {
    case 1 -> "一";
    case 2 -> "二";
    case 3 -> "三";
    default -> "其他";  // 必須有 default
};

搭配 enum 使用

Switch Expression 與 enum 搭配非常好用:

enum Operation { ADD, SUBTRACT, MULTIPLY, DIVIDE }

int calculate(Operation op, int a, int b) {
    return switch (op) {
        case ADD -> a + b;
        case SUBTRACT -> a - b;
        case MULTIPLY -> a * b;
        case DIVIDE -> {
            if (b == 0) {
                throw new ArithmeticException("除數不能為零");
            }
            yield a / b;
        }
    };
}

// 使用
System.out.println(calculate(Operation.ADD, 10, 5));       // 15
System.out.println(calculate(Operation.MULTIPLY, 10, 5));  // 50

回傳不同型別

Switch Expression 的所有分支必須回傳相同或相容的型別:

// 正確:所有分支都回傳 String
String result = switch (value) {
    case 1 -> "一";
    case 2 -> "二";
    default -> "其他";
};

// 正確:int 和 double 相容,結果是 double
double number = switch (type) {
    case "int" -> 100;
    case "double" -> 99.9;
    default -> 0;
};

不回傳值的 Switch Expression

雖然名為 Expression,但也可以不回傳值,單純用於執行程式碼:

int action = 2;

switch (action) {
    case 1 -> System.out.println("新增");
    case 2 -> System.out.println("編輯");
    case 3 -> System.out.println("刪除");
    default -> System.out.println("無效操作");
}
// 編輯

這種用法結合了箭頭語法的簡潔,但不需要賦值給變數。

null 處理 (Java 21+)

Java 21 開始,switch 可以直接處理 null 值:

String str = null;

String result = switch (str) {
    case null -> "空值";
    case "hello" -> "你好";
    case "bye" -> "再見";
    default -> "其他";
};

System.out.println(result);  // 空值

在 Java 21 之前,對 null 進行 switch 會拋出 NullPointerException

Pattern Matching (Java 21+)

Java 21 正式支援 switch 的 Pattern Matching:

Object obj = "Hello";

String result = switch (obj) {
    case Integer i -> "整數: " + i;
    case String s -> "字串: " + s;
    case Double d -> "浮點數: " + d;
    case null -> "空值";
    default -> "未知類型";
};

System.out.println(result);  // 字串: Hello

搭配 when 條件

Object obj = 25;

String result = switch (obj) {
    case Integer i when i < 0 -> "負數";
    case Integer i when i == 0 -> "零";
    case Integer i when i > 0 -> "正數";
    case String s when s.isEmpty() -> "空字串";
    case String s -> "字串: " + s;
    case null -> "空值";
    default -> "其他";
};

System.out.println(result);  // 正數

Record Pattern (Java 21+)

搭配 Record 類型進行解構:

record Point(int x, int y) {}

Object obj = new Point(10, 20);

String result = switch (obj) {
    case Point(int x, int y) when x == 0 && y == 0 -> "原點";
    case Point(int x, int y) when x == y -> "對角線上";
    case Point(int x, int y) -> "座標: (" + x + ", " + y + ")";
    default -> "不是 Point";
};

System.out.println(result);  // 座標: (10, 20)

實用範例

HTTP 狀態碼處理

int statusCode = 404;

String message = switch (statusCode) {
    case 200 -> "OK";
    case 201 -> "Created";
    case 400 -> "Bad Request";
    case 401 -> "Unauthorized";
    case 403 -> "Forbidden";
    case 404 -> "Not Found";
    case 500 -> "Internal Server Error";
    case 502 -> "Bad Gateway";
    case 503 -> "Service Unavailable";
    default -> "Unknown Status: " + statusCode;
};

System.out.println(message);  // Not Found

計算器

double calculate(double a, String operator, double b) {
    return switch (operator) {
        case "+", "add" -> a + b;
        case "-", "subtract" -> a - b;
        case "*", "multiply" -> a * b;
        case "/", "divide" -> {
            if (b == 0) throw new ArithmeticException("除數不能為零");
            yield a / b;
        }
        case "%", "mod" -> a % b;
        case "^", "power" -> Math.pow(a, b);
        default -> throw new IllegalArgumentException("未知運算子: " + operator);
    };
}

System.out.println(calculate(10, "+", 5));   // 15.0
System.out.println(calculate(2, "^", 10));   // 1024.0

命令解析器

record Command(String action, String[] args) {}

void executeCommand(Command cmd) {
    switch (cmd.action()) {
        case "help" -> {
            System.out.println("可用命令:");
            System.out.println("  help - 顯示說明");
            System.out.println("  list - 列出項目");
            System.out.println("  add <item> - 新增項目");
            System.out.println("  exit - 離開程式");
        }
        case "list" -> System.out.println("目前項目: " + Arrays.toString(cmd.args()));
        case "add" -> {
            if (cmd.args().length > 0) {
                System.out.println("新增: " + cmd.args()[0]);
            } else {
                System.out.println("錯誤:請指定要新增的項目");
            }
        }
        case "exit" -> {
            System.out.println("再見!");
            System.exit(0);
        }
        default -> System.out.println("未知命令: " + cmd.action());
    }
}

版本對照

功能Java 版本
Switch Expression (Preview)Java 12, 13
Switch Expression (正式)Java 14
yield 關鍵字Java 14
Pattern Matching (Preview)Java 17, 18, 19, 20
Pattern Matching (正式)Java 21
null caseJava 21
when 條件Java 21

重點整理

  • Switch Expression 是 Java 14 引入的新語法,可以回傳值
  • 使用 箭頭語法 (->) 更簡潔,自動避免 fall-through
  • 多行程式碼使用 yield 回傳值
  • 多個 case 可用逗號合併:case 1, 2, 3 ->
  • 必須處理所有可能的值(完整性檢查)
  • Java 21+ 支援 Pattern Matchingnull 處理
  • 建議在 Java 14+ 專案中優先使用 Switch Expression