JDK 17 switch模式匹配

这是我参与11月更文挑战的第10天,活动详情查看:2021最后一次更文挑战

欢迎关注公众号OpenCoder,来和我做朋友吧~❤😘😁🐱‍🐉👀

简介

Pattern Matching for switch(Preview)

在switch中使用模式匹配,预览版本。

预览版本

  • 有可能在之后的版本删除
  • 有可能计划进一步增强

在 Java 16 中, JEP 394 扩展了 instanceof 运算符以采用类型模式并执行模式匹配。

1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码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 标签,那么我们可以更清晰可靠地重写上述代码

1
2
3
4
5
6
7
8
9
java复制代码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**


    逐行校验![](https://gitee.com/songjianzaina/juejin_p13/raw/master/img/f9a18f38d6c4c00327145a2c2d7bdbce99d13ae4df0fefe58e61a00acfd0bde6)


    - **switch**


    直接到default![](https://gitee.com/songjianzaina/juejin_p13/raw/master/img/8e06dce3c57de5c7fe6cbd3beb5516f56d4026bff99c5a33a80b88eb02e95bf7)
  • switch模式匹配的目标
+ 通过允许模式出现在 case 中,扩展 switch 表达式和语句的表现力和适用性。
+ 允许switch的case使用null
+ 引入两种新的模式:保护模式,允许使用任意布尔表达式来改进模式匹配逻辑,以及带括号的模式,以解决一些解析歧义。
+ 确保所有现有的 switch 表达式和语句在没有更改的情况下继续编译并以相同的语义执行。
+ 确保和旧版本switch表达式和语句的兼容性

语法

增强 switch 语句和表达式两种方式

  • 扩展case语句中除常量外,还可以使用模式匹配
  • 除了案例中的模式,还有两种新的模式:保护模式和括号模式。

对于模式匹配有四个特点

  • 增强的类型检查:选择器表达式的类型包括:基本类型或任何引用类型(包括null)。
1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码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 表达式和语句的完整性
+ 存在子父类关系
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
java复制代码// 错误
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
java复制代码// 错误
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
java复制代码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语句
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
java复制代码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】,它允许通过任意布尔表达式对模式进行细化。
    • 括号模式:给任意布尔表达式加上括号,以避免解析歧义
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
java复制代码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,其他 ->
1
2
3
4
5
6
7
8
9
10
11
12
13
14
java复制代码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密封类

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%