likes
comments
collection
share

在Java如何使用模式匹配和密封类

作者站长头像
站长
· 阅读数 19

本文探讨如何使用模式匹配和密封类来提高 Java 代码质量。Java 模式匹配可让您在处理复杂数据结构时编写更简洁、更易读的代码。它简化了从数据结构中提取数据并对其执行操作的过程。让我们深入了解有关模式匹配和密封类的更多信息。

Java 中的模式匹配是什么?

模式匹配将值与包含变量和条件的模式进行匹配。如果值与模式匹配,则值的相应部分将绑定到模式中的变量。这可以使代码更易读、更直观。

模式匹配有两种类型:传统模式匹配和现代模式匹配。让我们在以下部分中看看两者之间的区别。

传统模式匹配

在传统的模式匹配中,通过添加带有模式参数的关键字,switch语句可以扩展为支持模式匹配。该语句可以匹配原始类型、包装器、枚举和字符串。case``switch

例如:

private static void printGreetingBasedOnInput(String input){
        switch (input){
            case "hello":
                System.out.println("Hi There");
                break;
            case "goodbye":
                System.out.println("See you Later!");
                break;
            case "thank you":
                System.out.println("You are welcome");
                break;
            default:
                System.out.println("I don't understand");
                break;
        }
    }

Java 方法printGreetingBasedOnInput接受一个input字符串,并使用 switch-case 语句根据其值打印相应的问候语。它涵盖了“你好”、“再见”和“谢谢”的情况,提供适当的响应,对于其他输入则默认为“我不明白”。

现代模式匹配

在现代模式匹配中,switch语句可以匹配各种模式,如任何类型的对象、枚举或基元。case关键字用于指定要匹配的模式。

private static void printGreetingBasedOnInput(String input){
        switch (input){
            case "hello" -> System.out.println("Hi There");
            case "goodbye" -> System.out.println("See you Later!");
            case "thank you" -> System.out.println("You are welcome");
            default -> System.out.println("I don't understand");
        }
    }

此代码片段使用更简洁的语法。它通过直接指定要为每个 case 标签执行的操作来简化代码。

在 Java 16 之前,我们需要检查对象的类型,然后将其显式转换为变量。Java instanceof16 中引入的增强运算符既可以验证类型,也可以对变量执行隐式转换,如下例所示:

private static void printType(Object input){
        switch (input) {
            case Integer i -> System.out.println("Integer");
            case String s -> System.out.println("String!");
            default -> System.out.println("I don't understand");
        }
    }

在使用模式保护时,增强instanceof变得特别有价值。模式保护是一种通过包含布尔表达式使 Java 模式匹配中的 case 语句更加具体的方法。

这允许对模式匹配方式进行更细粒度的控制,并使代码更具可读性和表现力。

private static void printType(Object input){                                                 
    switch (input) {                                                                         
        case Integer i && i > 10 -> System.out.println("Integer is greater than 10");        
        case String s && !s.isEmpty()-> System.out.println("String!");                       
        default -> System.out.println("Invalid Input");                                      
    }                                                                                        
}                                                                                            

基于上面的例子,您可以看到 Java 模式匹配提供了各种好处:

  • 它允许有效地匹配值与模式并提取数据,从而提高代码的可读性。
  • 它通过使用单段代码处理不同情况来减少代码重复。
  • 它通过启用值与特定类型的匹配来增强类型安全性。
  • 可以在案例中使用模式保护来进一步增强代码的可读性和可维护性。

Java 中的密封类是什么?

密封类允许开发人员限制可以扩展或实现给定类或接口的类集。

密封类提供了一种创建类或接口层次结构的方法,这些类或接口只能由一组指定的类进行扩展或实现。

例如:

public sealed class Result permits Success, Failure {
    protected String response;

    public String message(){
        return response;
    }
}

public final class Success extends Result {

    @Override
    public String message() {
        return "Success!";
    }
}

public final class Failure extends Result {

    @Override
    public String message() {
        return "Failure!";
    }
}

在这个例子中,我们定义了一个名为的密封类,Result它可以通过SuccessFailure类进行扩展。

任何尝试扩展的其他类Result都将导致编译错误。

这提供了一种限制可用于扩展的类集的方法Result,使得代码更易于维护和扩展。

需要记住的几个要点:

  • 在 Java 中,如果一个子类想成为密封类的允许子类,那么它必须和密封类定义在同一个包中。如果子类没有定义在同一个包中,就会产生编译错误。
  • 如果允许子类扩展 Java 中的密封类,则它必须具有以下三个修饰符之一:final、sealed 或 non-sealed。
  • 密封子类必须定义与其密封超类相同或更严格的一组允许子类。密封子类必须是 final 或密封的。非密封子类不得作为密封超类的允许子类,并且所有允许子类都必须与密封超类属于同一包。

如何结合 Java 模式匹配和密封类

您可以在具有模式匹配的 switch 语句中使用密封类及其允许的子类。

这样可以让代码更简洁,更容易阅读。下面是一个例子:

private static String checkResult(Result result){                                     
    return switch (result) {                                                          
        case Success s -> s.message();                                                
        case Failure f -> f.message();                                                
        default -> throw new IllegalArgumentException("Unexpected Input: " + result); 
    };                                                                                
}                                                                                     

对于密封类,编译器需要模式匹配中的一个默认分支来确保覆盖所有可能的情况。

由于密封类具有一组固定的允许子类,因此可以用有限数量的 case 语句覆盖所有情况。

如果不包含默认分支,将来可能会向层次结构添加新的子类,而现有 case 语句不会涵盖该子类。这将导致运行时错误,从而难以调试。

通过要求默认分支,编译器可以确保代码完整并涵盖所有可能的情况,即使将来在密封类层次结构中添加了新的子类。

这有助于防止运行时错误并使代码更加健壮和易于维护。

如果我们修改该类Result以包含一个名为的新子类Pending,而我们没有将其包含在我们的模式匹配中,那么它将被默认分支覆盖。

Java 中的密封接口是什么?

当使用 Java 中的密封接口时,如果涵盖所有情况,编译器将不需要模式匹配中的默认分支。

如果缺少分支,编译器将需要一个默认分支来确保处理所有可能的情况。

使用密封类时,我们始终需要包含默认分支。以下是代码示例:

public sealed interface OtherResult permits Pending, Timeout {
    void message();
}

public final class Pending implements OtherResult{
    @Override
    public void message() {
        System.out.println("Pending!");
    }
}

public final class Timeout implements OtherResult{
    @Override
    public void message() {
        System.out.println("Timeout!");
    }
}

private static void checkResult(OtherResult result){
        switch (result) {
            case Pending p -> p.message();
            case Timeout t -> t.message();
        };
    }

结论

以下是在 Java 代码中使用模式匹配和密封类的一些要点:

  • 提高可读性:模式匹配和密封类可以使代码更具表现力和更易于阅读,因为它们允许更简洁和直观的语法。
  • 更好地控制类层次结构:密封类提供了一种控制类层次结构的方法,并确保只能使用允许的子类。这可以提高代码安全性和可维护性。
  • 隐式类型安全:模式匹配和密封类提供隐式类型安全,可以降低运行时错误的风险并使代码更易于维护。
  • 减少代码重复:模式匹配和密封类可以在一段代码中处理不同的情况,从而减少代码重复。
  • 更好的代码组织: 密封类可以通过将相关类组合在一起来帮助组织代码并降低类层次结构的复杂性。
  • 提高可维护性: 模式匹配和密封类可以使代码更易于理解和更新,从而提高代码的可维护性,从长远来看可以节省时间和精力。
转载自:https://juejin.cn/post/7394643241851060251
评论
请登录