日食虫?仅使用默认大小写打开空值

2022-09-01 10:57:27

我正在试验,我发现以下功能在Eclipse上编译和运行良好(Build id:20090920-1017,不确定确切的编译器版本):enum

public class SwitchingOnAnull {
    enum X { ,; }
    public static void main(String[] args) {
        X x = null;
        switch(x) {
            default: System.out.println("Hello world!");
        }
    }
}

当使用 Eclipse 编译和运行时,它会正常打印和退出。"Hello world!"

对于编译器,这将引发一个预期的结果。javacNullPointerException

那么Eclipse Java编译器中是否存在错误?


答案 1

这是一个错误。下面是根据 Java 语言规范第 3 版为语句指定的行为:switch

JLS 14.11 交换机语句

SwitchStatement:
    switch ( Expression ) SwitchBlock

执行语句时,首先计算 。如果计算结果为 ,则抛出 a,并且由于这个原因,整个语句突然完成。switchExpressionExpressionnullNullPointerExceptionswitch

显然,Eclipse中的错误与大小写无关,或者根本没有关系。defaultenum

public class SwitchingOnAnull {
    public static void main(String[] args) {        
        java.math.RoundingMode x = null;
        switch(x) {};

        switch((Integer) null) {};

        switch((Character) null) {
            default: System.out.println("I've got sunshine!");
        }       
    }
}

上面的代码在Eclipse(至少是某些版本)上编译并“良好”运行。每个人都会在编译时抛出一个,这与规范的要求完全一致。switchNullPointerExceptionjavac


原因

以下是在 Eclipse 下编译时:javap -c SwitchingOnAnull

Compiled from "SwitchingOnAnull.java"
public class SwitchingOnAnull extends java.lang.Object{
public SwitchingOnAnull();
Code:
 0: aload_0
 1: invokespecial  #8; //Method java/lang/Object."<init>":()V
 4: return

public static void main(java.lang.String[]);
Code:
 0: aconst_null
 1: astore_1
 2: getstatic     #16; //Field java/lang/System.out:Ljava/io/PrintStream;
 5: ldc           #22; //String I've got sunshine!
 7: invokevirtual #24; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
10: return

}

Eclipse 编译器似乎完全摆脱了整个构造。不幸的是,这种优化违反了语言规范。switch


官方说法

该错误已归档并分配以进行修复。

奥利维尔·托曼 2010-05-28 08:37:21 EDT

我们在优化方面过于激进。

为:

  switch((Integer) null) {};

当我们至少应该计算表达式时,我们优化整个语句。switch

我来看看。

3.6.1 的候选项。

另请参见


答案 2

当然。如果我们看一下java语言规范的第14.11章,它清楚地指出(在“讨论”下):

禁止使用 null 作为开关标签可以防止编写永远无法执行的代码。如果 switch 表达式属于引用类型(如盒装基元类型或枚举),则当表达式在运行时计算结果为 null 时,将发生运行时错误。