switch 语句也是Java 支持的两种选择语句之一,也属于多分支语句。它提供了一种简便的方法,可以根据表达式的值将执行流程导向代码的不同部分。因此,它往往能提供一种比大量 “if-else-if” 语句更为优美的解决方案。而且从 JDK 14 版本开始,switch 语句得到了显著的增强和扩展,新增了多项功能,远远超出了其传统形式的范畴。
首先先看看传统switch语句的语法及使用上的注意点。
22.1 传统switch语句
传统switch语句的语法如下:
switch(表达式){
case 常量1:
语句1;
break;
case 常量2:
语句2;
case 常量n:
语句n…;
default:
默认语句;
}
语法解释
此处switch后小括号中的表达式可以是变量、有运算符参与运算的表达式、有方法调用等,此处统一使用表达式指代。在实际开发中,通常会使用变量。目前Java支持的数据类型有:byte、short、char、int 这4个数值类型及其包装类、enum(枚举)、String,对象等。
而在 case 后紧跟的只能是常量(字面量和final修饰的变量),且不能重复,另外其数据类型要与 switch 后表达式的数据类型兼容,不能超过switch表达式中数据类型的范围。
case 后的语句加不加大括号都行,执行时会作为一个整体依次执行其中的语句。实际开发中一般不加大括号。
break 和 default 是可省的。且default只能出现一次,位置可以随意,一般放最后。
执行流程说明
1、首先计算 switch 后表达式的值,然后从上往下依次比较其与 case 常量(case关键字后的常量)是否相等,如果相等,则执行 case 后面的语句。基本数据类型使用 == 运算符比较是否相等,引用数据类型使用 equals 方法判断是否相等。
2、遇到某个 case 常量与 switch 后的表达式相等时,执行某个case后语句,遇到 break 则直接终止整个 switch 语句的执行二不再与后续 case 常量对比。
由于break关键字是可省的,如果 case语句中没有break语句,就不再与后续 case常量对比会继续执行后面case对应的语句,直到遇到某个case语句中的break或执行完整个switch语句。这称之为穿透(fall through)。
3、如果所有case常量都不能与 switch 后的表达式相等,则执行 default 后的语句,达到兜底的效果。
案例:根据给定的月份,输出该月份是大月、小月还是平月。
String monthInfo;
int month = 10;
switch (month) {
case 1:
monthInfo = "大月";
break;
case 2:
monthInfo = "平月";
break;
case 3:
monthInfo = "大月";
break;
case 4:
monthInfo = "小月";
break;
case 5:
monthInfo = "大月";
break;
case 6:
monthInfo = "小月";
break;
case 7:
monthInfo = "大月";
break;
case 8:
monthInfo = "大月";
break;
case 9:
monthInfo = "小月";
break;
case 10:
monthInfo = "大月";
break;
case 11:
monthInfo = "小月";
break;
case 12:
monthInfo = "大月";
break;
default:
monthInfo = "无效月份";
}
System.out.println(month + "月是" + monthInfo);
上述代码中,当给定的月份是10月时,依次与case后的 1 - 12 进行比较,直到和10相等,则会将变量 monthInfo 赋值为10,随机结束这整个 switch 语句,执行到第 45 行输出结果。如果月份不是合法的月份,会执行到 default 语句将变量 monthInfo 赋值为"无效月份"。
上面的代码中规中矩,将 1-12 依次与 month 比较,如果稍加改动则代码更简洁:
String monthInfo;
int month = 10;
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
monthInfo = "大月";
break;
case 4:
case 6:
case 9:
case 11:
monthInfo = "小月";
break;
case 2:
monthInfo = "平月";
break;
default:
monthInfo = "无效月份";
}
System.out.println(month + "月是" + monthInfo);
上面代码利用了没有break时的穿透,将相同逻辑的代码合在一处,比如月份是1月或3月都没有任何语句需要执行,当然用也没有遇到break,那么代码会一直执行到case 12 后的两句代码,为monthInfo赋值为"大月",然后执行 break,随即结束整个switch语句。
可以看到与之前版本比较,重复代码更少,可读性也更好。
22.2 比较if语句与switch语句
if 语句和 switch 语句都是 Java 支持的选择语句,那么它们之间有何异同呢?
相同点当然就是都可以实现条件结构。
不同点
- switch 语句只能处理等值的条件判断
- if 语句除了能处理等值的条件判断,还可以处理变量处于某个区间时的情况
简而言之:if 语句一定可以替代 switch 语句,但是反之不一定成立。比如:
int num = 1;
if(num < 100){
// ...
}
上述第2 行的判断使用 switch 语句则无法实现。因为可能的值太多,每一个放在case中不现实。
22.3 传统的switch/case结构存在的问题
仔细观察之前传统的switch语句,会发现存在几个问题:
- 多个条件对应相同逻辑代码时,要重复写多个case
- break可省,一旦忘记可能会有编译器检测不到的逻辑错误
- 变量作用域混乱(case后的多条语句作为一个整体执行但不一定是代码块)
前面两点比较好理解,关于第三点,看以下代码片段:
int num = 10;
switch (num) {
case 1:
int n = 0;
case 2:
int n = 0; // n 重复声明导致编译错误
}
case 1 和 case 2 后的变量声明语句中,n 重复了会导致语法错误。当然加了大括号就没有问题了,两个大括号就形成了各不相干的代码块。
int num = 10;
switch (num) {
case 1: {
int n = 0;
}
case 2: {
int n = 0;
}
}
22.4 switch表达式
从 JDK 14 版本开始,引入了一个称为 switch 表达式(Switch Expression) 的新特性,Java 17 ,Java 21 一级 Java 25 都对此都进行了改进,它的作用包括:
- 简化代码编写
- 提高可读性
- 避免潜在的错误
下面通过几种不同的语法来介绍 switch 表达式的基本用法,涉及到模式匹配的暂不介绍。
switch表达式语法-1
switch(表达式){
case 常量1 -> 语句或代码块;
……
case 常量n -> 语句或代码块;
default -> 语句或代码块;
}
每一个 -> 后面跟语句或代码块,代码块中声明的变量有自己的作用域。
case后可以使用多个以逗号分隔的常量。
与第一个案例相同:根据给定的月份,输出该月份是大月、小月还是平月。
String monthInfo;
int month = 10;
switch (month) {
case 1, 3, 5, 7, 8, 10, 12 -> monthInfo = "大月";
case 4, 6, 9, 11 -> monthInfo = "小月";
case 2 -> monthInfo = "平月";
default -> monthInfo = "无效月份";
}
System.out.println(monthInfo);
逻辑就不解释了,很好理解,语法上,如果case后要执行多条语句,则必须使用大括号形成代码块,就避免了作用域混乱的问题。
switch表达式语法-2
下面的语法形式中每一个 -> 后面跟一个表达式,可以在某个case条件成立时,直接将表达式的值作为整个switch表达式执行的结果返回,可以赋值给合适类型的变量。
变量 = switch(表达式){
case 常量1 -> 表达式1;
……
case 常量n -> 表达式n;
default -> 默认表达式;
};
还是刚才的案例:
int month = 10;
String monthInfo = switch (month) {
case 1, 3, 5, 7, 8, 10, 12 -> "大月";
case 4, 6, 9, 11 -> "小月";
case 2 -> "平月";
default -> "无效月份";
};
System.out.println(monthInfo);
上述代码更加简洁,以第 3 行为例,当month为1, 3, 5, 7, 8, 10, 12中其中一个时,直接将"大月"作为返回值赋值为前面的变量 monthInfo。
switch表达式语法-3
如果在case 语句后的代码块有多行,或许要进行较为复杂的运算后,才有结果返回,就不适合使用表达式直接返回了,要使用代码块,且代码块中有返回值。
变量 = switch(表达式){
case 常量1 -> 带有返回值的代码块;
……
case 常量n -> 带有返回值的代码块;
default -> 带有返回值的代码块;
};
上述语法中每一个 -> 后面跟一个代码块,且代码块中要使用 yield 关键字返回数据,该数据作为整个 switch 表达式的返回结果。
int month = 10;
String monthInfo = switch (month) {
case 1, 3, 5, 7, 8, 10, 12 -> {
System.out.println("无意义的输出");
yield "大月";
}
case 4, 6, 9, 11 -> "小月";
case 2 -> "平月";
default -> "无效月份";
};
System.out.println(monthInfo);
在第3行的case语句后的代码块中,有两行语句,如果需要在最后将结果返回的话,要是用 yield 关键字。
22.5 小结
Java中的switch语句是一种多分支选择结构,支持byte、short、char、int等基本类型及枚举、String等对象类型。传统switch语法通过case常量匹配执行对应代码块,break可控制穿透现象。JDK14后引入的switch表达式通过"->"箭头语法简化代码,支持多case合并、代码块作用域隔离,并能直接返回值。相较于if语句,switch仅适用于等值判断,但代码更简洁。新特性解决了传统switch存在的重复case、break遗漏、变量作用域混乱等问题,提供了更灵活的编程方式。

被折叠的 条评论
为什么被折叠?



