2015-08-12 4 views
7

fand ich ein seltsames Verhalten in der aktuellen Version von Java 8.em Meiner Meinung nach dem folgenden Code sollte in Ordnung sein, aber die JVM wirft ein NullPointerException:Nullpointer statt Null (? JVM Bug)

Supplier<Object> s =() -> false ? false : false ? false : null; 
s.get(); // expected: null, actual: NullPointerException 

Es Es spielt keine Rolle, welche Art von Lambda-Ausdruck es ist (selbe mit java.util.function.Function) oder welche generischen Typen verwendet werden. Anstelle von false ? : können auch aussagekräftigere Ausdrücke verwendet werden. Das obige Beispiel ist sehr kurz. Hier ist ein buntes Beispiel:

Function<String, Boolean> f = s -> s.equals("0") ? false : s.equals("1") ? true : null; 
f.apply("0"); // false 
f.apply("1"); // true 
f.apply("2"); // expected: null, actual: NullPointerException 

jedoch diese Codestück gut laufen:

Supplier<Object> s =() -> null; 
s.get(); // null 

und

Supplier<Object> s =() -> false ? false : null; 
s.get(); // null 

Oder mit Funktion:

Function<String, Boolean> f = s -> { 
    if (s.equals("0")) return false; 
    else if (s.equals("1")) return true; 
    else return null; 
}; 
f.apply("0"); // false 
f.apply("1"); // true 
f.apply("2"); // null 

ich mit zwei getestet Java-Versionen:

~# java -version

openjdk Version "1.8.0_66-intern" OpenJDK Runtime Environment (build 1.8.0_66-internal-b01) OpenJDK 64-Bit Server VM (Build 25.66-b01, mixed mode)

C:\>java -version

java version "1.8.0_51" Java (TM) SE Runtime Environment (bauen 1.8.0_51-b16) Java HotSpot (TM) 64-Bit Server VM (Build 25.51-b03, mixed mode)

+4

Wie unterscheidet sich das von "Objekt a = falsch? falsch: falsch? false: null; 'was auch eine' NullPointerException' ergibt? –

+0

Es tritt in Java 7 und Java 8 (OpenJDK) auf. –

+1

@ bayou.io Wie so? Lambdas fügen nichts hinzu. Das "Problem" sind ternäre Ausdrücke. –

Antwort

7

Das hat nichts mit Lambda-Ausdrücke zu tun; es ist einfach, dass der Rückgabetyp des ternären Operators in diesem Fall boolean ist, so dass automatisches Unboxing verwendet wird.

NPE wird auch hier geworfen:

public class Main { 

    private static Object method() { 
     return false ? false : false ? false : null; 
    } 

    public static void main(String[] args) { 
     System.out.println(method()); 
    } 
} 

Also, was genau hier passiert?

Erstens ‚eingebettet‘ Ausdruck (false ? false : null) gemäß JLS §15.25 ausgewertet:

Der Bedingungsoperator ist syntaktisch richtige assoziatives ( es Gruppen von rechts nach links). A b: c? D: e? F: g bedeutet also dasselbe wie a? B: (c? D: (e? F: g)).

Der Typ des eingebetteten Ausdruck ist Boolean (boolean eingerahmt), so dass sowohl false und null hinein passen.

Dann wird der ganze Ausdruck ist:

false ? false : (Boolean expression) 

dann wieder nach JLS §15.25:

Wenn einer der zweiten und dritten Operanden von primitivem Typ T ist, und die Art der der andere ist das Ergebnis der Anwendung der Box-Umwandlung (§5.1.7) auf T, dann ist der Typ des Bedingungsausdrucks T.

So ist das erste Argument der Urtyp boolean (T in der Spezifikation), die Art des anderen ist die eingerahmte T (Boolean), so dass der Typ des gesamten Ausdrucks ist boolean.

Anschließend wird der eingebettete Ausdruck in Runtime zu null ausgewertet, die automatisch auf boolean, die NPE verursacht.

+1

nun, der OP-Code ist in Java8, also müssen wir die Zieleingabe 'Objekt' in Betracht ziehen , und wir müssen analysieren, ob es Operanden beeinflussen sollte; warum Unboxing statt Boxen gemacht wird. – ZhongYu

+0

Warum ist dann 'falsch? falsch: falsch? Boolean.FALSE: null; 'werfen immer noch eine NPE. Der zweite Operand des verschachtelten Ausdrucks ist 'Boolean', daher wird keine Box-Konvertierung angewendet (§5.1.7). Der äußere Ausdruck wäre "falsch? false: (Boolescher Ausdruck) '. Die nächste Zeile in JLS §15.25 lautet: "Wenn einer der zweiten und dritten Operanden vom Nulltyp ist und der Typ des anderen ein Referenztyp ist, dann ist der Typ des Bedingungsausdrucks dieser Referenztyp." OK, aber endlich das wäre gleich "falsch"? false: (Boolean) null '. – steffen

+1

'falsch? falsch: falsch? Boolean.FALSE: null' ist das Gleiche. Der eingebettete ternäre Ausdruck wird zu 'Boolean' ausgewertet, und der gesamte Ausdruck gibt 'boolean' zurück, da es sich um den oben genannten primitiven Typ' T' handelt. –

Verwandte Themen