大家好,我是指北君。
Java 17 引入了针对 switch
表达式和语句的模式匹配(JEP 406)。模式匹配在 switch
条件定义时提供了更多的灵活性。在模式匹配之前,switch
只支持精确匹配一个常量值的选择器表达式。在本文中,我们来看看三种可以在switch
语句中应用的不同模式类型。
Switch 表达式
我们在 Java 中使用switch
来做一些策略的选择,哪个语句被选中取决于 switch
表达式的值。
在 Java 17 之前版本中,Switch
的表达式必须是一个数字、一个字符串或一个常数。而且 case
只能包含常数。
1 |
|
在上面例子中,如果变量b不是 final 类型的话,编译器会抛出一个常量表达式要求的错误。
模式匹配
模式匹配最初是在 Java 14 中首次作为预览功能引入的。但是只限于模式的一种形式 – 类型模式。一个典型的模式由一个类型名和要绑定结果的变量组成。将类型模式应用于instanceof
操作简化了类型检查和构造。
1 |
|
这种内置的语言增强有助于我们写出更少的代码,并增强可读性。
Switch 的模式匹配
用于instanceof
的模式匹配在Java 16中成为一个永久性的功能。 到了Java 17, 模式匹配的应用才扩展到了switch
表达式。 它仍然是一个预览特性,所以我们如果要使用的话,还得弃用预览功能。
1 |
|
在Switch中使用类型模式
让我们来看看类型模式和instanceof
操作符如何在switch
语句中应用。 我们先创建一个方法,使用if-else
语句将不同的类型转换为double
。如果该类型不被支持,我们的方法将简单地返回0。
1 |
|
我们可以通过switch
中的类型模式来改造上面的方法,用更少的代码解决同样的问题。
1 |
|
在Java1 17版本之前, Switch
表达式只局限于几种类型。现在有了类型模式,Switch
表达式可以是任何类型啦。
保护模式
类型模式帮助我们根据特定的类型来转移控制,然而,有时候我们也需要对传递的值进行额外的检查。我们可以在 case 中使用一个if
语句来检查一个String
的长度等。
1 |
|
我们可以用保护模式来解决同样的问题,可以使用模式和布尔表达式的组合。
1 |
|
保护模式使我们能够避免在switch
语句中附加if
条件,我们可以把条件逻辑移到case标签中。
括号模式
除了在case标签中设置条件逻辑外,括号模式能使我们对其分组。在执行额外的检查时,我们可以简单地在我们的布尔表达式中使用括号。
1 |
|
通过使用括号,我们可以避免出现额外的if-else
语句。
switch 的一些特殊点
现在我们来看看在switch
中使用模式匹配时需要考虑的几个特殊情况。
5.1.覆盖所有的值
当在switch
中使用模式匹配时,Java 编译器会检查类型覆盖问题。 举个例子,switch
条件接受任何对象,但只覆盖String
情况。
1 |
|
我们的例子将导致以下编译错误
1 |
|
这是因为switch
case标签需要包括选择器表达式的类型。
对子类排序
在switch
中使用模式匹配的子类时,case 的顺序就很重要了。举个例子,String
案例在CharSequence
案例之后。
1 |
|
由于String
是CharSequence
的一个子类,我们的例子将导致以下编译错误。
1 |
|
这个错误背后的原因是,没有机会执行到第二种情况,因为任何传递给方法的字符串对象都会在第一种情况下处理。
null 的处理
在Java17之前版本中,向switch
语句传递一个null
值都会导致一个NullPointerException
。现在通过类型模式,现在可以将空值检查作为一个单独的case标签来处理。
1 |
|
如果没有针对空值的案例标签,那么object的模式标签也是可以匹配空值的。
1 |
|
我们需要注意的是一个switch
表达式不能同时具有null
情况和 object
情况。 如果同时存在就会报编译错误。
1 |
|
最后,一个使用模式匹配的switch
语句仍然可以抛出一个NullPointerException
。
总结
在这篇文章中,我们探讨了switch
表达式和语句的模式匹配,这是Java 17
中的一个预览功能,通过在 case
标签中使用模式,来做出更多有效率的事情。