为啥不完整的switch表达式编译成功

Posted

技术标签:

【中文标题】为啥不完整的switch表达式编译成功【英文标题】:Why does an incomplete switch expression compile successfully为什么不完整的switch表达式编译成功 【发布时间】:2019-04-22 04:56:47 【问题描述】:

试用JDK/12 EarlyAccess Build 20,其中JEP-325 Switch Expressions 已集成为预览功能。表达式的示例代码(在 JEP 中也是如此):

Scanner scanner = new Scanner(System.in);
Day day = Day.valueOf(scanner.next().toUpperCase());
int i = switch (day) 
    case MONDAY,TUESDAY, WEDNESDAY:
        break 0;
    default:
        System.out.println("Second half of the week");
        // ERROR! Group doesn't contain a break with value
;

我试图按照上一个问题中关于如何Compile a JDK12 preview feature with Maven 并使用命令行执行上述代码块的相同程序:

java --enable-preview -jar target/jdk12-updates-1.0.0-SNAPSHOT.jar

出乎我的意料,我收到了以下错误:

Error: Unable to initialize main class
com.***.nullpointer.expression.SwitchExpressionMustComplete
Caused by: java.lang.VerifyError: Bad local variable type Exception
Details:   Location:
    com/***/nullpointer/expression/SwitchExpressionMustComplete.main([Ljava/lang/String;)V @66: iload   
Reason:
    Type top (current frame, locals[4]) is not assignable to integer   
Current Frame:
    bci: @66
    flags:  
    locals:  '[Ljava/lang/String;', 'java/util/Scanner', 'com/***/nullpointer/Day' 
    stack:     
Bytecode:
    0000000: bb00 0259 b200 03b7 0004 4c2b b600 05b8
    0000010: 0006 4db2 0007 2cb6 0008 2eaa 0000 001f
    0000020: 0000 0001 0000 0003 0000 0019 0000 0019
    0000030: 0000 0019 0336 04a7 000b b200 0912 0ab6
    0000040: 000b 1504 3eb1                        
Stackmap Table:
    append_frame(@52,Object[#2],Object[#34])
    same_frame(@58)
    same_frame(@66)

我知道该文档指出代码是错误的,用break 1; 替换评论可以解决它,但我的问题是:

第一季度。 为什么编译阶段同样成功?那不应该在编译时失败吗?

第二季度。我看到如此详细的错误消息的原因是什么? --enable-preview 功能会对此负责吗?

【问题讨论】:

【参考方案1】:

这是一个已知的错误。见JDK-8212982 有关其状态的详细信息。

这段代码:

public class SwitchBug  

    static String hold(String item)  
        return switch(item)  
            case String s ->  System.out.println(s);  
            default -> "temp"; 
        ; 
     

    public static void main(String[] args)  
        System.out.println(hold("bug")); 
     

编译并生成:

bug 
temp 

此程序不应编译,因为第一个案例正常完成。

【讨论】:

嗯,不知道这些是如何链接的,但相反,这个错误报告中的代码实际上无法为我编译并出现错误:or -> expected .... not a statement 问题的另一部分怎么样,我看到这么详细的错误信息是什么原因? (并不是我担心看到它,只是想知道我是否可以使用一些 JVM 标志来切换到此视图以报告错误。) @Naman 在这个答案的例子中,错误的情况是在一个返回值的情况之前,所以代码流到达后面的情况并执行它,错误地返回那个值。在您的问题示例中,错误的后面没有案例,因此它使局部变量未初始化。但显然,您的实际代码包含之后尝试使用该变量的尝试,并且具有将使用未初始化变量的代码路径会使字节码无效。所以代码被 JVM 的验证器拒绝,你看到的是带有 HotSpot 诊断的VerifyError @Holger 实际上,我在 switch 表达式之后使用了变量,很高兴知道我得到这些详细日志的原因。感谢您分享详细信息。

以上是关于为啥不完整的switch表达式编译成功的主要内容,如果未能解决你的问题,请参考以下文章

switch结构case语句后的多个语句必须放在花括号中。 这句话对吗?为啥?

为啥 Switch 需要语句但接受表达式

php中switch以下输出结果为啥是1 不是0?

为啥很多程序员不用switch,而是大量的if……else if?

Go之switch分支控制

为啥编译的 python 正则表达式比较慢?