Java学习之旅第一季-22:控制语句之switch语句

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遗漏、变量作用域混乱等问题,提供了更灵活的编程方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值