switch 语句的模式匹配 - Sip of Java

经过几个预览阶段,switch 的模式匹配已在 JDK 21 中作为最终功能发布!在 switch 中添加模式匹配将为开发人员在使用 switch 时提供许多生活质量改进。让我们来看看吧!

模式匹配

模式匹配最初是在 Java 16 中添加的,用于 instanceof 的模式匹配。用于 instanceof 的模式匹配确实显著提高了代码可读性和可维护性,但在比较多个类型时仍然存在一些不足,例如以下示例

interface Shape{
    double area();
}
record Circle(double diameter) implements Shape{...};
record Square(double side) implements Shape{...};
Shape shape = new Circle(10); 
String message; 
if(shape instanceof Circle c) {
   message = "A circle with area of " + c.area();
} else if (shape instanceof Square s) {
   message = "A square with area of " + s.area();
} else {
   message = "Unknown shape";
}

在 Java 21 中,switch 已扩展为允许 case 标签也成为模式,从而简化了之前的示例,如下所示

interface Shape{
    double area();
}
record Circle(double diameter) implements Shape{...};
record Square(double side) implements Shape{...};
Shape shape = new Circle(10); 
String message = switch(shape){
    case Circle c -> "A circle with area of " + c.area();
    case Square s -> "A square with area of " + s.area();
    default -> "Unknown shape";
};

保护条件

随着模式匹配的更新,switch 可以使用保护条件进一步细化 case 标签。这可以通过将检查条件保留在 case 标签内(而不是在 case 块内使用 if 语句)来帮助提高代码的可读性和可维护性;以下示例演示了如何使用保护条件

interface Shape{
    double area();
}
record Circle(double diameter) implements Shape{...};
record Square(double side) implements Shape{...};
Shape shape = new Circle(10);
String message = switch(shape){
   case Circle c when c.area() > 100 
	-> "A large circle with area of " + c.area(); 
   case Circle c -> "A circle with area of " + c.area();
   case Square s -> "A square with area of " + s.area();
   default -> "Unknown shape";
};

处理 null

在对 switch 进行更新后,null 也作为 case 标签得到支持。这有助于提高可读性和可维护性,因为所有与 switch 相关的逻辑都可以在 switch 的主体中涵盖,而无需在之前进行 null 检查

interface Shape{
    double area();
}
record Circle(double diameter) implements Shape{...};
record Square(double side) implements Shape{...};
Shape shape = new Circle(10); 
String message = switch(shape){
    case Circle c -> "A circle with area of " + c.area();
    case Square s -> "A square with area of " + s.area();
    case null -> "Null value";
    default -> "Unknown shape";
};

穷举性

switch 中使用模式匹配时,即使像以下示例一样写成语句,switch 也必须是穷举的

interface Shape{
   double area();
}
record Circle(double diameter) implements Shape{...};
record Square(double side) implements Shape{...};
Shape shape = new Circle(10);
switch(shape){
  case Circle c -> System.out.println("A circle with area of " + c.area());
  case Square s -> System.out.println("A square with area of " + s.area());
  default -> System.out.println("Unknown shape");
};

密封层次结构

switch 中使用密封层次结构时,编译器可以读取层次结构以测试穷举性。在此示例中,default case 是不必要的,因为所有路径都被 switch 涵盖。这可以帮助防止错误,因为如果将来向密封层次结构中添加新类,这将导致此代码出现编译器错误。

sealed interface Shape{
    double area();
}
record Circle(double diameter) implements Shape{...};
record Square(double side) implements Shape{...};
Shape shape = new Circle(10);
String message = switch(shape){
   case Circle c -> "A circle with area of " + c.area();
   case Square s -> "A square with area of " + s.area();   
   //No default needed; compiler can read sealed hierarchy
};

记录模式

记录模式也成为 Java 21 中的最终功能,并在 switch 中得到支持

record Name(String fName, String lName, String mName) {};
Name host = new Name("William","Korando",37);
String printName = switch(host) {
	case Name(var fName, var lName, var mName) -> lName + ", " + fName + " " + mName;
};

其他阅读材料

switch 的模式匹配 - JEP 441

记录模式 - JEP 440

instanceof 的模式匹配 - JEP 394

祝您编码愉快!