我正在尝试使用enum
,我发现以下编译并在Eclipse上运行正常(Build id:20090920-1017,不确定编译器版本是否正确):
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!"
并正常退出。
使用javac
编译器,会按预期抛出NullPointerException
。
Eclipse Java编译器中是否存在错误?
答案 0 :(得分:27)
这是一个错误。以下是根据 Java语言规范,第3版的switch
语句的指定行为:
switch
Statement SwitchStatement: switch ( Expression ) SwitchBlock
执行
switch
语句时,首先评估Expression
。如果Expression
评估为null
,则会抛出NullPointerException
,并且整个switch
语句因此突然完成。
显然,Eclipse中的错误与default
个案或enum
完全无关。
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(至少某些版本)上编译并运行“正常”。使用switch
编译时,每个人NullPointerException
都会抛出javac
,这与规范要求完全相同。
在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
构造。不幸的是,这种优化打破了语言规范。
该错误已归档并已分配用于修复。
Olivier Thomann 2010-05-28 08:37:21 EDT
我们对优化过于激进。
有关:
switch((Integer) null) {};
当我们至少应该评估时,我们会优化整个
switch
语句 表达我会看看。
3.6.1的候选人。
答案 1 :(得分:4)
Definitly。如果我们查看java语言规范的chapter 14.11,它会明确指出(在'讨论'下):
禁止使用null作为 一个开关标签阻止了一个 编写永远不会的代码 执行。如果切换表达式是 参考类型,例如盒装 原始类型或枚举,运行时 如果表达式将发生错误 在运行时计算为null。
答案 2 :(得分:1)
是的。根据JLS,这是一个错误:
如果switch表达式是引用类型,例如盒装基元类型或枚举,如果表达式在运行时求值为null,则会发生运行时错误。