2016-06-23 6 views
3

Javaプログラミングで三項条件式を使用するのは好きですが、問題が発生しました:nullを返して参照型に代入される三項条件式がNullPointerExceptionを引き起こすのはなぜですか?

次のコードは小さな例ですが、見つかった問題を示しています。

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

? –

+3

そこに 'if-then-else'文がありません。あなたは*三項演算子*を持っています。 – Andreas

+0

NPEの重要な質問です! –

答えて

5

これは三条件式のタイプを決定するJLS rulesの結果:第二及び第三のオペランドの一方はプリミティブ型Tであり、および他のタイプに適用した結果である場合

をTへボクシング変換(§5.1.7)は、その後、条件式のタイプは、このルールは、三元表現のタイプはdoubleなくDoubleであることを意味するT.

あります。 a.getY()メソッドによって返されたDoubledoubleにアンボックスすると、が返されるため、NullPointerExceptionが返されます。

a == null ? 0.0 : a.getY(); 
      double Double  -> hence the type of the ternary expression is double 
+0

ありがとうございますが、nullpointerexceptionは型の例外ではありません – Paul

+0

@Paul:そうですが、基本的な原因はEranのタイプです:コンパイラは(ルールから)3番目のオペランドの型が 'double 'を呼び出すと、NPEをスローするメソッド呼び出し(' .doubleValue() ')を挿入して' a.getY() 'の結果を自動的にアンボックスします。 –

+0

@Paul 'a.getY()メソッドによって返されたDoubleをUnboxするとNullPointerExceptionが発生します。 – Eran

4

0.0はタイプdouble、ないDoubleであるので、それは起こります。条件演算子への第2の2つのオペランドが同じ型でなければならないので、オートボクシング/アンボクシングはそれに来て、コンパイラは、その中にコードを回し:次にためa.getY()戻りnull、およびスローどの...

x = Double.valueOf(a == null ? 0.0 : a.getY().doubleValue()); 
// -^^^^^^^^^^^^^^^--------------------------^^^^^^^^^^^^^^ 

コードdoubleValuenullに呼び出しようとします。

我々はコードを逆コンパイルするjavap -c Exampleを実行した場合、我々は(私が太字に入れました)これらの呼び出しを見ることができます:IF-THEN-ELSEある

 
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 
} 
+0

大きな説明。内部を示すため+1。 – Sanjeev

関連する問題