2016-06-23 14 views
3

Ich verwende gerne den ternären bedingten Ausdruck in Java-Programmierung, aber ich habe ein Problem festgestellt:Warum verursacht ein ternärer Bedingungsausdruck, der null zurückgibt und einem Referenztyp zugewiesen ist, eine NullPointerException?

Der folgende Code ist ein kleines Beispiel, aber es zeigt das Problem, das ich gefunden habe.

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(); 
    } 

} 

Was verursacht die NullPointerException?

+2

Wo liegt if-then-else? –

+3

Sie haben dort keine 'if-then-else'-Anweisung. Sie haben einen * ternären Operator *. – Andreas

+0

Eine nicht-triviale NPE-Frage! –

Antwort

5

dies aus den JLS rules Ergebnissen des Typs des ternären bedingten Ausdrucks Bestimmung:

Wenn einer der zweiten und dritten Operanden von primitivem Typ T ist, und die Art des andere ist das Ergebnis des Anwendens Boxen Umwandlung (§5.1.7) zu T, wird der Typ des bedingten Ausdrucks ist T.

Diese Regel bedeutet, dass die Art des ternären Ausdruck ist double und nicht Double. Wenn Sie das von Ihrer a.getY()-Methode zurückgegebene Double auf double zurücksetzen, wird NullPointerException verursacht, da diese Methode null zurückgibt.

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

Ok danke, aber ich habe nullpointerexception nicht type exception – Paul

+0

@Paul: Richtig, aber die Grundursache ist der Typ Kram, den Eran erwähnt: Weil der Compiler entscheidet (aus den Regeln), dass der dritte Operand vom Typ 'double sein soll ', es entpackt automatisch das Ergebnis von' a.getY() 'durch Einfügen eines Methodenaufrufs (' .doubleValue() '), der die NPE auslöst. –

+0

@Paul 'Das Deaktivieren des Double, das von Ihrer a.getY() -Methode zurückgegeben wird, führt zu einer doppelten NullPointerException' – Eran

4

Es geschieht, weil 0.0 vom Typ double, nicht Double. Die zweiten zwei Operanden zu dem bedingten Operator müssen vom gleichen Typ sein, so Autoboxing/Unboxing kam hinein und der Compiler drehte diesen Code in:

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

... das wirft, weil a.getY() kehrt null, und dann die Code versucht, doubleValue auf null aufzurufen.

Wenn wir javap -c Example führen Sie den Code zu dekompilieren, können wir diese Anrufe sehen (ich habe sie in fett) setzen:

 
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

Große Erklärung. +1 für das Anzeigen von Interna. – Sanjeev