为什么返回null并分配给引用类型的三元条件表达式会导致NullPointerException?

时间:2016-06-23 06:41:31

标签: java if-statement nullpointerexception

我喜欢在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

的原因

2 个答案:

答案 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
}