日食错误?仅使用默认情况打开 null
我正在尝试使用 enum
,我发现以下在 Eclipse 上编译并运行良好(Build id:20090920-1017,不确定确切的编译器版本):
公共类 SwitchingOnAnull {枚举 X { ,;}公共静态无效主要(字符串[]参数){X x = 空;开关(x){默认值:System.out.println("Hello world!");}}}
当使用 Eclipse 编译和运行时,它会打印 "Hello world!"
并正常退出.
使用 javac
编译器,这会按预期抛出 NullPointerException
.
那么 Eclipse Java 编译器有 bug 吗?
解决方案这是一个错误.这是根据 Java 语言规范,第 3 版为 switch
语句指定的行为:
JLS 14.11 开关
声明
<块引用>SwitchStatement:switch ( 表达式 ) SwitchBlock
当执行 switch
语句时,首先评估 Expression
.如果 Expression
的计算结果为 null
,则抛出 NullPointerException
并且整个 switch
语句因此突然完成.
显然 Eclipse 中的错误与 default
case 或 enum
完全无关.
公共类 SwitchingOnAnull {公共静态无效主要(字符串[]参数){java.math.RoundingMode x = null;开关(x){};开关((整数)空){};开关((字符)空){默认值:System.out.println("我有阳光!");}}}
上面的代码在(至少某些版本的)Eclipse 上编译并正常"运行.当使用 javac
编译时,每个单独的 switch
都会抛出 NullPointerException
,这正是规范要求的.
原因
这里是在Eclipse下编译时的javap -c SwitchingOnAnull
:
编译自SwitchingOnAnull.java"公共类 SwitchingOnAnull 扩展 java.lang.Object{公共 SwitchingOnAnull();代码:0:aload_01:调用特殊#8;//方法java/lang/Object."<init>":()V4:返回公共静态无效主(java.lang.String[]);代码:0: 常量_null1:astore_12:获取静态#16;//字段 java/lang/System.out:Ljava/io/PrintStream;5:最不发达国家#22;//String 我有阳光!7:调用虚拟#24;//方法java/io/PrintStream.println:(Ljava/lang/String;)V10:返回}
Eclipse 编译器似乎完全摆脱了整个 switch
结构.不幸的是,这种优化违反了语言规范.
官方说法
该错误已提交并分配修复.
<块引用>Olivier Thomann 2010-05-28 08:37:21 EDT
我们在优化上过于激进.
为:
switch((Integer) null) {};
我们优化了整个 switch
语句,当我们至少应该评估表达.
我去看看.
3.6.1 的候选人.
另见
- 错误 314830 - 打开
null
表达式不会'不总是抛出NullPointerException
I was experimenting with enum
, and I found that the following compiles and runs fine on Eclipse (Build id: 20090920-1017, not sure exact compiler version):
public class SwitchingOnAnull {
enum X { ,; }
public static void main(String[] args) {
X x = null;
switch(x) {
default: System.out.println("Hello world!");
}
}
}
When compiled and run with Eclipse, this prints "Hello world!"
and exits normally.
With the javac
compiler, this throws a NullPointerException
as expected.
So is there a bug in Eclipse Java compiler?
解决方案This is a bug. Here's the specified behavior for a switch
statement according to the Java Language Specification, 3rd Edition:
JLS 14.11 The switch
Statement
SwitchStatement: switch ( Expression ) SwitchBlock
When the
switch
statement is executed, first theExpression
is evaluated. If theExpression
evaluates tonull
, aNullPointerException
is thrown and the entireswitch
statement completes abruptly for that reason.
Apparently the bug in Eclipse has nothing to do with default
case or enum
at all.
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!");
}
}
}
The above code compiles and runs "fine" on (at least some version of) Eclipse. Each individual switch
throws a NullPointerException
when compiled with javac
, which is exactly as the specification mandates.
The cause
Here's javap -c SwitchingOnAnull
when compiled under Eclipse:
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
}
It seems that the Eclipse compiler gets rid of the entire switch
constructs entirely. Unfortunately this optimization breaks the language specification.
The official words
The bug has been filed and assigned for fix.
Olivier Thomann 2010-05-28 08:37:21 EDT
We are too aggressive on the optimization.
For:
switch((Integer) null) {};
we optimize out the whole
switch
statement when we should at least evaluate the expression.I'll take a look.
Candidate for 3.6.1.
See also
- Bug 314830 - Switching on a
null
expression doesn't always throwNullPointerException
相关文章