在 Java 17 switch-case 中使用 final 变量的好处

Posted

技术标签:

【中文标题】在 Java 17 switch-case 中使用 final 变量的好处【英文标题】:Benefit of using final variables in Java 17 switch-case 【发布时间】:2022-01-15 22:51:30 【问题描述】:

有人能告诉我 Java 17 接受 final 表达式作为 switch-case-constructs 中的 case 表达式但不接受 final 表达式作为参数传递的好处吗?

    void test(int distinction, final int foo) 
        final var bar = 2;
        
        switch (distinction) 
        case foo -> doSomething(); // does not compile -> case expressions must be constant expressions
        case bar -> doSomething(); // does compile
        case 3 -> doOtherThings(); // does compile
        
    

为什么编译器不接受案例 1,尽管 foo 和 bar 一样是最终变量?

在我看来,案例 3 的可读性比案例 2 好得多。所以我看不到新语言结构的好处。

【问题讨论】:

【参考方案1】:

案例标签必须是编译时间常数。最终参数不是编译时常量;它可能不会随着方法的给定调用而变化,但它可以随着方法的调用而变化。 (最终实例字段和没有初始化器的静态最终字段也不是编译时常量。)

【讨论】:

【参考方案2】:

您的陈述“所以我没有看到新语言结构的好处”包含了涉及新语言结构的错误假设。

definition of compile-time constants 自 Java 1.0 以来没有改变。

常量变量是基本类型的final 变量或String 类型的变量,它使用常量表达式(§15.29) 进行初始化。

因此,与流行的顽固神话相反,编译时常量不必是 static,也根本不需要是字段。用常量表达式初始化的final 局部变量是编译时常量。相反,从不具有初始化程序的参数永远不会是编译时常量。

此外,switch 标签必须是整数类型时的编译时常量的规则永远不会改变。这更难识别,因为添加了对其他大小写标签的支持,Java 5 引入了切换 enum 类型的可能性,Java 7 增加了对切换 String 值的支持,并且新的模式匹配将允许切换超过类型。在enum 或类型标签的情况下,大小写标签不是编译时常量,而是不变的符号名称,因此在切换enum 或类型时根本不能使用变量名称。

因此,以下程序适用于每个 Java 版本:

class SwitchTest 
    public static void main(String[] args) 
        final int one = 1, two = 2;
        switch(args.length) 
          case one: System.out.println("one"); break;
          case two: System.out.println("two"); break;
          case one + two: System.out.println("three"); break;
        
    

这里不需要实际的用例。拥有简单而一致的规则比拥有试图排除看似无用的组合的复杂规则要好。

作为附录,由于Java 5引入了注解,以下是合法代码

class Test 
    @interface Example  String value(); 
    public static void main(String[] args) 
        final String str = "test";
        @Example(str) class Local 
    

这证明了规则的一致性。注解要求值是编译时常量,因此如果变量是编译时常量,则可以在注解中使用局部变量。

【讨论】:

以上是关于在 Java 17 switch-case 中使用 final 变量的好处的主要内容,如果未能解决你的问题,请参考以下文章

Java中的switch-case语句

有啥完美的方法替代java中的 if-else,switch-case

在Android library中不能使用switch-case语句访问资源ID的原因分析及解决方案

Java:通过字节码看if-else和switch-case

有啥完美的方法替代java中的 if-else,switch-case

如何在 Django 模板中获得“switch-case”语句功能?