首页 / Java 入门教程 / switch 分支

Java 入门教程

switch 分支

本教程共 100 篇 · 第 20 篇 · 更新于 2026-08-05 · 约 6 分钟阅读

JavaJava 入门教程switch语句switch表达式多路选择

20. switch 分支

本节目标:当判断条件是一连串”等于某个固定值”的选择时,用 switch 比层层 if 更清爽。学会传统 switch 的写法、看懂穿透陷阱,并掌握 Java 14 起正式可用的 switch 表达式新语法。

if 擅长”大于小于”这类范围判断,可有些场景是”等于 A 怎么做、等于 B 怎么做”。比如游戏菜单选 1 单人、2 多人、3 退出,这种多路相等匹配,用 switch 更合适。

传统 switch 的写法

switch 后面跟一个表达式,JVM 拿它的结果去挨个比对 case,命中哪个就从这个 case 往下执行,直到遇到 break 才停。

public class Main {
    public static void main(String[] args) {
        int option = 1;
        switch (option) {
            case 1:
                System.out.println("单人模式");
                break;
            case 2:
                System.out.println("多人模式");
                break;
            case 3:
                System.out.println("退出游戏");
                break;
            default:
                System.out.println("无效选项");
        }
    }
}
```bash

`default` 是"以上都没命中"时的兜底,类似 `if` 里的最后一个 `else`。

## 穿透效应:别漏写 break

这是传统 `switch` 最容易翻车的地方。`case` 本身没有花括号,一旦命中,后面的语句会**一路执行下去**,这就是"穿透"。漏写 `break` 时:

```java
int option = 2;
switch (option) {
    case 1: System.out.println("1");
    case 2: System.out.println("2");
    case 3: System.out.println("3");
    default: System.out.println("other");
}

option = 2 会连着打印出 23other。因为从 case 2 进入后没遇到 break,就势如破竹冲到底。

Warning

任何时候都记得给每个 casebreak。如果确实想让几个 case 共用一段逻辑(比如 2 和 3 都做同一件事),故意让它们”穿透”是可以的,但这种写法要加注释说明,免得别人(或一个月后的你)误以为是漏写了。

switch 能匹配什么类型

传统 switch 的表达式结果得是以下类型之一:

  • 整数类:byteshortcharint(及它们的包装类)
  • 字符串 String
  • 枚举 enum

字符串匹配是比较”内容相等”,这点比 == 安全:

String fruit = "apple";
switch (fruit) {
    case "apple":  System.out.println("苹果"); break;
    case "pear":   System.out.println("梨");   break;
    default:       System.out.println("其他水果");
}
```bash

> [!NOTE]
> 注意 `long`、`float`、`double`、布尔值**不能**直接做 switch 的表达式。需要的话先转成能匹配的类型,或者改用 `if`。

## switch 表达式(Java 14 正式)

传统写法要手写 `break`、容易穿透,于是 Java 12 开始引入、到 **Java 14 正式定为标准特性**的 `switch` 表达式,用箭头 `->` 改写,自动保证只走匹配的那一支,再也不用 `break`:

```java
String fruit = "apple";
switch (fruit) {
    case "apple" -> System.out.println("苹果");
    case "pear"  -> System.out.println("梨");
    case "mango" -> {
        System.out.println("芒果");
        System.out.println("好选择");
    }
    default -> System.out.println("其他水果");
}

箭头后面如果有多条语句,用 {} 包起来。新语法没有穿透效应,命中即止。

用 switch 表达式直接给变量赋值

新语法的杀手锏,是它能当表达式用,直接返回一个值赋给变量:

String fruit = "pear";
int opt = switch (fruit) {
    case "apple"        -> 1;
    case "pear", "mango" -> 2;   // 多个值用逗号合并
    default             -> 0;
};
System.out.println("opt = " + opt);
```bash

对比传统写法要先用 `int opt;` 声明,再在每个 `case` 里赋值加 `break`,新语法干净太多了。

## yield:在分支里返回复杂结果

如果某个分支要算好几步才能得出返回值,用 `{}` 包起来,再用 `yield` 把值交出来:

```java
String fruit = "orange";
int opt = switch (fruit) {
    case "apple" -> 1;
    case "pear", "mango" -> 2;
    default -> {
        int code = fruit.hashCode();
        yield code;   // 把这个值作为整个 switch 的返回值
    }
};

yield 的作用类似方法里的 return,只不过它返回的是 switch 表达式的值。

新旧写法怎么选

对比项传统 switch(case:switch 表达式(->
引入版本Java 1.0 起Java 14 正式(12/13 预览)
分支结束必须手写 break自动结束
穿透风险有,漏写 break 就穿
能否当值用不能,只能在分支里赋值能,int x = switch(...) {...};
多值合并靠连写空 case 穿透逗号分隔 case "a", "b" ->
分支多行直接写,靠 break 收尾{} 包住,yield 交值
穷尽性检查不检查当值用时强制覆盖全部或带 default
建议历史兼容,不推荐新写主线推荐

同一段逻辑,两种写法摆一起看得最清楚:

// 历史兼容写法,不推荐
int days;
switch (month) {
    case 1: case 3: case 5: case 7:
    case 8: case 10: case 12:
        days = 31;
        break;
    case 4: case 6: case 9: case 11:
        days = 30;
        break;
    default:
        days = 28;
}

// Java 14 起的推荐写法
int days = switch (month) {
    case 1, 3, 5, 7, 8, 10, 12 -> 31;
    case 4, 6, 9, 11           -> 30;
    default                    -> 28;
};
```bash

上面那段要先声明 `int days;`、每支赋值、每支 `break`,漏一个 `break` 结果就错;下面这段一次成型,`days` 还能直接写成 `final`。

> [!TIP]
> 新项目一律用 **switch 表达式(箭头语法)**,不用写 `break`、不会穿透、能直接赋值,既安全又简洁。传统 `case ... break` 写法当作"历史兼容"认识即可,读老代码时看得懂就行。

## 再往前一步:模式匹配 switch

Java 21 起,`switch` 的 `case` 还能直接匹配**类型**,不再局限于固定值:

```java
Object obj = 42;
String desc = switch (obj) {
    case Integer i -> "整数 " + i;
    case String s  -> "字符串,长度 " + s.length();
    default        -> "其他类型";
};

case Integer i 的意思是「如果 objInteger,就把它转好类型装进变量 i」,省掉了以前 instanceof 加强制转换那两步。这块要配合多态和 sealed 类才好发挥,第 43、48 章会再碰到,现在知道 switch 已经进化到这一步就够了。

小结:switch 适合多路相等匹配;传统写法务必写 break 防穿透;Java 14 起的 switch 表达式用 ->、可 yield 返回值,是主线推荐写法。

动手练一练

switch 把”星期几”映射到”今天吃什么”:周一到周五食堂,周六火锅,周日外卖。先用传统 case + break 写一遍,体会漏写 break 时的”穿透”现象;再改成 Java 14 的 switch 表达式箭头写法,对比哪种更清爽。

Tip

想验证穿透,故意删掉一个 break,输入那个 case 的值,看输出是不是”连着后面几个 case 一起打印了”。亲眼看到穿透,才真正理解为什么传统写法离不开 break

易错提醒

第一,传统 switch 忘了 break 会穿透,这是历史包袱,能写新表达式就别用老写法。第二,switch 的表达式在 Java 里支持的类型有限:早期只能 byteshortcharint 和对应的包装类、enum、字符串;Java 之后还支持 long 吗?不支持——long 不能做 case。记不住就记住:常用就是 intStringenum。第三,新表达式每个分支都要覆盖所有可能,或带 default,否则编译器报错。

拓展:switch 表达式的 yield 与枚举

Java 14 的 switch 表达式除了箭头 ->,还能用 yield 返回值:在大括号里写逻辑后 yield 值;。当某个分支要执行多行代码再返回时,yield 比箭头更合适。例如 case 1: { int x = calc(); yield x; }

另外 switch 配合 enum 枚举类型非常搭:把”星期""状态”定义成枚举,用 switch 分支处理,编译器还能帮你检查是否漏了某个枚举值。记住 switch 支持的类型是有限的(int、String、enum 及少量兼容类型),long、浮点数、boolean 都不能做 case——需要这些时,老老实实用 if

常见疑问

Q:什么时候用 switch,什么时候用 if

判断是「等于某几个固定值」就用 switch,是「落在某个区间」就用 if。成绩分档要写 score >= 90,这是范围判断,switch 干不了;菜单选项 1/2/3 是相等匹配,switch 比三个 else if 清爽。

Q:case 后面能写变量吗?

不能,必须是编译期常量——字面量、final 常量或枚举值。写变量会报错:

error: constant expression required
        case n -> "命中";
             ^
```text

要按变量比较,改用 `if`。

**Q:`switch` 表达式漏了分支会怎样?**

当值用时编译器强制要求穷尽。少写 `default` 又没覆盖全部可能:

```text
error: the switch expression does not cover all possible input values

对枚举来说,这条规则是白送的保险:以后往枚举里加了新常量,所有相关 switch 立刻编译报错,提醒你补上处理逻辑,不会静悄悄走到 default 里出错。

Q:case 里能不能不写 default

作为语句用(不取值)可以省,命中不了就整段跳过。当表达式取值时不能省,除非分支已经覆盖了枚举的全部常量。