这是我参与11月更文挑战的第10天,活动详情查看:2021最后一次更文挑战
欢迎关注公众号OpenCoder,来和我做朋友吧~❤😘😁🐱🐉👀
简介
Pattern Matching for switch(Preview)
在switch中使用模式匹配,预览版本。
预览版本
- 有可能在之后的版本删除
- 有可能计划进一步增强
在 Java 16 中, JEP 394 扩展了 instanceof 运算符以采用类型模式并执行模式匹配。
static String formatter(Object o){
String formatted = "unknown";
if (o instanceof Integer i) {
formatted = String.format("int %d", i);
} else if (o instanceof Long l) {
formatted = String.format("long %d", l);
} else if (o instanceof Double d) {
formatted = String.format("double %f", d);
} else if (o instanceof String s) {
formatted = String.format("String %s", s);
}
return formatted;
}
在Java 17中, JEP406
switch 是模式匹配的完美匹配!如果我们扩展 switch 语句和表达式以适用于任何类型,并允许使用模式而不是常量进行 case 标签,那么我们可以更清晰可靠地重写上述代码
static String formatterPatternSwitch(Object o) {
return switch (o) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> o.toString();
};
}
-
好处
-
语义更清晰:“参数 o 最多匹配以下条件之一”
-
在这种情况下,我们更有可能在 O(1) 时间内执行调度(==效率高==)。我们用断点调试这两段代码
-
if...else
逐行校验
-
switch
直接到default
-
-
-
switch模式匹配的目标
- 通过允许模式出现在 case 中,扩展 switch 表达式和语句的表现力和适用性。
- 允许switch的case使用null
- 引入两种新的模式:保护模式,允许使用任意布尔表达式来改进模式匹配逻辑,以及带括号的模式,以解决一些解析歧义。
- 确保所有现有的 switch 表达式和语句在没有更改的情况下继续编译并以相同的语义执行。
- 确保和旧版本switch表达式和语句的兼容性
语法
增强 switch 语句和表达式两种方式
- 扩展
case语句中除常量外,还可以使用模式匹配 - 除了案例中的模式,还有两种新的模式:保护模式和括号模式。
对于模式匹配有四个特点
-
增强的类型检查:选择器表达式的类型包括:基本类型或任何引用类型(包括null)。
Point(int i, int j) {} enum Color { RED, GREEN, BLUE; } static void typeTester(Object o) { switch (o) { case null -> System.out.println("null"); case String s -> System.out.println("String"); case Color c -> System.out.println("Color with " + Color.values().length + " values"); case Point p -> System.out.println("Record class: " + p.toString()); case int[] ia -> System.out.println("Array of ints of length" + ia.length); default -> System.out.println("Something else"); } } -
switch 表达式和语句的完整性
- 存在子父类关系
// 错误 static void error(Object o) { switch(o) { case CharSequence cs -> System.out.println("A sequence of length " + cs.length()); case String s -> // 编译错误 - CharSequence是String的父类,提示该模式已经由前一个模式匹配 System.out.println("A string: " + s); default -> { break; } } } // 正确 static void error(Object o) { switch(o) { case String s -> System.out.println("A string: " + s); case CharSequence cs -> System.out.println("A sequence of length " + cs.length()); default -> { break; } } }- 缺少default
// 错误 static int coverage(Object o) { return switch (o) { // 编译错误,类型匹配不完整,缺少default case String s -> s.length(); case Integer i -> i; }; } // 正确 static int coverage(Object o) { return switch (o) { case String s -> s.length(); case Integer i -> i; default -> 0; }; }-
类型匹配检查
sealed是密封类的语法,我们会在文章后续进行探讨。
表示可以实现接口S的类有 A,B,C
sealed interface S permits A, B, C {} final class A implements S {} final class B implements S {} final class C implements S {} // 错误 static void switchStatementComplete(S s) { switch (s) { // 编译错误,缺少类型B case A a : System.out.println("A"); break; case C c : System.out.println("C"); break; }; } // 正确 static int testSealedCoverage(S s) { return switch (s) { case A a -> 1; case B b -> 2; case C c -> 3; }; } -
模式变量声明的范围
- case语句后箭头右侧可以出现的内容:
- 表达式
- 代码块
- throw语句
- case语句后箭头右侧可以出现的内容:
static void test(Object o) {
switch (o) {
case Character c -> { // 代码块
if (c.charValue() == 7) {
System.out.println("Ding!");
}
System.out.println("Character");
}
case Integer i -> // throw语句
throw new IllegalStateException("Invalid Integer argument of value " + i.intValue());
default -> {
break;
}
}
}
- 保护模式和括号模式。
- 保护模式:我们可以添加一种称为保护模式的新模式,写作 【表达式1】 && 【表达式2】,它允许通过任意布尔表达式对模式进行细化。
- 括号模式:给任意布尔表达式加上括号,以避免解析歧义
class Shape {}
class Rectangle extends Shape {}
class Triangle extends Shape { int calculateArea() { ... } }
static void testTriangle(Shape s) {
switch (s) {
case null:
break;
case Triangle t:
if (t.calculateArea() > 100) {
System.out.println("Large triangle");
break;
}
default:
System.out.println("A shape, possibly a small triangle");
}
}
// 优化
static void testTriangle(Shape s) {
switch (s) {
case Triangle t && (t.calculateArea() > 100) -> // 括号模式
System.out.println("Large triangle");
case Triangle t ->
System.out.println("Small triangle");
default ->
System.out.println("Non-triangle");
}
}
- 处理null值
- 在case中可以使用null
- 以及null引出的新的模式:case null,其他 ->
static void test(Object o) {
switch (o) {
case null -> System.out.println("null!");
case String s -> System.out.println("String");
default -> System.out.println("Something else");
}
}
static void test(Object o) {
switch (o) {
case null,default -> //
System.out.println("Something else (包括null)");
}
}
参考资源
下期预告
下期我们将一起学习探讨Sealed Classes密封类