我喜欢在java编程中使用三元条件表达式,但我遇到了一个问题:
以下代码是一个小例子,但它显示了我找到的问题。
public class Example {
public Example() {
Double x = 0.0;
A a = new A();
x = a == null ? 0.0 : a.getY(); // Happens on this line
System.out.println(x);
}
class A {
Double y = null;
private Double getY() {
return y;
}
}
public static void main(String[] args) {
new Example();
}
}
导致NullPointerException
?
答案 0 :(得分:5)
这是由确定三元条件表达式类型的JLS rules得出的:
如果第二个和第三个操作数之一是原始类型T,而另一个操作数的类型是将装箱转换(第5.1.7节)应用于T的结果,则条件表达式的类型为T. / p>
此规则表示三元表达式的类型为double
而不是Double
。将Double
方法返回的a.getY()
拆箱至double
会导致NullPointerException
,因为该方法会返回null
。
a == null ? 0.0 : a.getY();
double Double -> hence the type of the ternary expression is double
答案 1 :(得分:5)
这是因为0.0
的类型为double
,而非Double
。条件运算符的后两个操作数必须是相同的类型,因此autoboxing / unboxing进入它并且编译器将该代码转换为:
x = Double.valueOf(a == null ? 0.0 : a.getY().doubleValue());
// -^^^^^^^^^^^^^^^--------------------------^^^^^^^^^^^^^^
...由于a.getY()
返回null
而引发,然后代码尝试在doubleValue
上调用null
。
如果我们运行javap -c Example
来反编译代码,我们可以看到这些调用(我将它们以粗体显示):
public class Example { public Example(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: dconst_0 5: invokestatic #2 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double; 8: astore_1 9: new #3 // class Example$A 12: dup 13: aload_0 14: invokespecial #4 // Method Example$A."":(LExample;)V 17: astore_2 18: aload_2 19: ifnonnull 26 22: dconst_0 23: goto 33 26: aload_2 27: invokestatic #5 // Method Example$A.access$000:(LExample$A;)Ljava/lang/Double; 30: invokevirtual #6 // Method java/lang/Double.doubleValue:()D 33: invokestatic #2 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double; 36: astore_1 37: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream; 40: aload_1 41: invokevirtual #8 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V 44: return public static void main(java.lang.String[]); Code: 0: new #9 // class Example 3: dup 4: invokespecial #10 // Method "":()V 7: pop 8: return }