java switch二三事

概述

switch是在java开发中一个很常用的关键字,一般用于对于一个变量等于不同值时候做不同的处理,比起直接用if、else if、else if、else这样会显得简洁一些,也更加符合人最直观的理解,加强代码的可读性。

传统用法

jdk7之前,switch只有1种用法,switch仅支持整形和枚举。实际上,枚举也是通过ordinal()方法转换成了int。所以,可以简单理解成仅支持整形。

穿透

相比于直接用if、else if、else if、else这样的写法,switch有个比较大的特点是穿透,即一旦符合条件进入了case,如果没有显示break,就会一直进入下面的case,例如我们要写个函数求月份归属的季节,代码如下:

csharp 复制代码
private static Season getSeasonByMonth(int month) {
    Season season = null;
    // 这里简单认为春季是2、3、4月,夏季是5、6、7月,秋季是8、9、10月,冬季是11、12、1月
    // 注意这里month的取值在0-11之间,是日常理解的月份-1
    switch (month) {
        case 1:
        case 2:
        case 3:
            season = Season.SPRING;
            break;
        case 4:
        case 5:
        case 6:
            season = Season.SUMMER;
            break;
        case 7:
        case 8:
        case 9:
            season = Season.AUTUMN;
            break;
        case 10:
        case 11:
        case 0:
            season = Season.WINTER;
            break;
        default:
            System.out.println("month值不合法,未能找到归属的季节");
    }
    return season;
}

这里就利用了穿透的特性,避免了代码重复。不过这种特性也带来了额外的成本,就是有点反直觉,天然认为不符合case条件就不会进入,忘记写break而导致代码bug是初级程序员使用switch常见的错误。

另外,使用switch时候,最后写上default是一个好习惯,作用跟else是类似的,可以确保这个switch语句逻辑完整,无论什么值,都会走到一种情况,即使在写的时候,觉得这个default永远也不会进去,但是程序异常往往会发生在这些意想不到的地方。

匹配String

从jdk1.7开始,switch支持String,不过这里其实只是新增的一个语法糖,switch String实际上是利用了String自身的hashCode()方法转换成了int,然后通过equles来保护哈希冲突的情况,实际上JVM层面依然还是只支持整形,跟switch 枚举有些类似。

jdk14的新用法

需要说明,以下的一些特性在jdk12、jdk13就已经开始预览,归于jdk14是因为在jdk14中才成为正式的特性。

yield返回值

switch语句之前仅仅是在某些情况下替代if,这里可以使用yield来设置返回值,switch就正式变成了表达式,上面的方法可以写成:

csharp 复制代码
Season season = switch (month) {
    case 1:
    case 2:
    case 3:
        yield Season.SPRING;
    case 4:
    case 5:
    case 6:
        yield Season.SUMMER;
    case 7:
    case 8:
    case 9:
        yield Season.AUTUMN;
    case 10:
    case 11:
    case 0:
        yield Season.WINTER;
    default:
        System.out.println("month值不合法,未能找到归属的季节");
        yield Season.SPRING;
};

case多值 和 箭头表达值

之前,我们想在switch等于某些值的时候执行相同的逻辑,我们会使用switch穿透的特性,但是这个特性是双刃剑,也比较容易出错,这里支持case多值之后,就有了更加简洁直观的写法,符合人的直觉,例如下面的方法可以改写成:

ini 复制代码
private Season getSeasonByMonth(int month) {
    Season season = null;
    // 这里简单认为春季是2、3、4月,夏季是5、6、7月,秋季是8、9、10月,冬季是11、12、1月
    // 注意这里month的取值在0-11之间,是日常理解的月份-1
    switch (month) {
        case 1, 2, 3 -> season = Season.SPRING;
        case 4, 5, 6 -> season = Season.SUMMER;
        case 7, 8, 9 -> season = Season.AUTUMN;
        case 10, 11, 0 -> season = Season.WINTER;
        default -> System.out.println("month值不合法,未能找到归属的季节");
    }
    return season;
}

jdk17的新用法

模式匹配

这里的模式匹配是指,可以通过传入对象的不同类型,来走不同的逻辑,而不是仅仅是不同的值,例如:

arduino 复制代码
String s1 = switch (o) {
    case Integer ii -> "o is Integer";
    case String ss -> "o is String, length = " + s.length();
    default -> "unknown";
};

注意,这里匹配了类型之后,可以用一个变量接收,这样可以直接使用类型自带的方法了,不然还需要对o进行一次强转,这样会更加方便。

保护模式

case条件不仅仅是一个值,还可以增加表达式进行综合判断,前面说过的支持switch String的语法糖就适合这种保护模式,因为还需要equles来进行一次保护校验

vbnet 复制代码
String s1 = switch (o) {
    case Integer ignored -> "o is Integer";
    case String ignored && "123".equals(o) -> "o is String";
    default -> "unknown";
};

空值

之前switch是无法接受空值的,传空就会抛出空指针异常,这里支持空值后,不需要在switch之前判空,空也可以作为一种值,跟其他的值一起并列:

csharp 复制代码
switch (s) {
    case "123":
        System.out.println("s is 123");
        break;
    case null:
        System.out.println("s is null");
        break;
}

总结

switch在java开发中是个历史悠久的关键字,也比较常用。传统用法时,注意穿透现象,以及写上default让逻辑完备。在更新版本的jdk中,可以使用case多值来代替之前的穿透,用yield或者箭头来做值返回。特定情况下模式匹配、保护模式、空值等新用法也会让代码更加简洁和易于理解。

说句题外话,既然新版本这么香,就不要一直守着java8不放了对不对,毕竟,不断尝试新的东西,也是一个程序猿基本的素养。

相关推荐
罗政3 分钟前
[附源码]超简洁个人博客网站搭建+SpringBoot+Vue前后端分离
vue.js·spring boot·后端
架构文摘JGWZ34 分钟前
Java 23 的12 个新特性!!
java·开发语言·学习
拾光师1 小时前
spring获取当前request
java·后端·spring
aPurpleBerry2 小时前
neo4j安装启动教程+对应的jdk配置
java·neo4j
我是苏苏2 小时前
Web开发:ABP框架2——入门级别的增删改查Demo
java·开发语言
xujinwei_gingko2 小时前
Spring IOC容器Bean对象管理-Java Config方式
java·spring
2301_789985942 小时前
Java语言程序设计基础篇_编程练习题*18.29(某个目录下的文件数目)
java·开发语言·学习
IT学长编程2 小时前
计算机毕业设计 教师科研信息管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·毕业设计·springboot·毕业论文·计算机毕业设计选题·计算机毕业设计开题报告·教师科研管理系统
m0_571957582 小时前
Java | Leetcode Java题解之第406题根据身高重建队列
java·leetcode·题解
程序猿小D2 小时前
第二百三十五节 JPA教程 - JPA Lob列示例
java·数据库·windows·oracle·jdk·jpa