Seltsames ternäres Java-Verhalten beim Zuweisen von Werten. Was macht Java hinter den Kulissen, damit dies geschieht?

10

Vor einigen Tagen stieß ich auf ein faszinierendes Szenario, in dem ich keine Dokumentation darüber finden konnte, wie oder warum Java Folgendes zulässt. (Dieses Snippet ist nur eine vereinfachte Form des Fehlers.)

    @Test
    public void test() {
      boolean bool = false;
      Integer intVal = Integer.valueOf(5);
      Long longVal = null;
      Long result = bool ? intVal : longVal;

      System.out.println(" > " + result);
   }

im obigen Ausschnitt:

Wenn der Bool = true ist, erhalten Sie den Wert '5'.

Wenn jedoch bool = false ist, wird beim Versuch, die ternäre Operation auszuwerten, eine Nullzeigerausnahme angezeigt. NICHT die Druckanweisung.


Um dies zu beheben, ändere ich einfach 'Ergebnis' in

Long result = bool ? Long.valueOf(intVal) : longVal;

Wenn Sie dies tun, erhalten Sie das erwartete Verhalten, das ich brauchte:

Wenn der Bool = true ist, erhalten Sie den Wert '5'.

aber wenn bool = false, dann erhalten Sie 'null'


Der lustige Teil ist nun, dass Java Sie NICHT kompilieren lässt, wenn Sie dies in eine normale if / else-Anweisung aufteilen

longVal = intVal; 

aber es fängt das nicht über den ternären Operator ab. Was macht Java also, um den Nullpunkt im ursprünglichen Snippet auf Null zu setzen?

(Java 11)

Tim Z.
quelle

Antworten:

10

Wenn Sie dies tun:

Long result = bool ? intVal : longVal

Dieser Ausdruck gibt ein zurück longund, wenn er boolfalsch ist, versucht er, die Box nullauf einen Long-Wert zu entpacken , um ihn an die resultVariable anzupassen , und löst eine NPE aus.

Wenn Sie dies tun:

Long result = bool ? Long.valueOf(intVal) : longVal

Dieser Ausdruck kehrt bereits zurück, Longes ist kein Entpacken erforderlich, und der nullWert wurde der resultVariablen erfolgreich zugewiesen .

Referenz:

Um besser zu verstehen, warum dies geschieht, lesen Sie die folgenden Abschnitte des JLS, um zu verstehen, warum dies geschieht:

Diego Magdaleno
quelle
Ich bin überrascht, dass Sie unterschiedliche Referenztabellen 15.25 A bis E haben, in denen "klar" ist, dass Integer / Long zu einem BNP (Integer, Long) führt.
Matt
Gute Antwort. Im Allgemeinen empfehle ich, wenn ich absolut keine Ahnung habe, was im Inneren vor sich geht, einen Blick in den kompilierten Bytecode zu werfen, der fast genau verrät, was beschrieben wurde. Zumindest beim Extrahieren eines minimalen Code-Snippets ist dies mehr oder weniger eine Frage des Trainings, des Lesens und Verstehens.
Jan Held
In Abschnitt 5.6.2 des JLS heißt es: "Wenn ein Operand von einem Referenztyp ist, wird er einer Unboxing-Konvertierung unterzogen." dann wird "Erweiterung der primitiven Konvertierung (§5.1.2) angewendet [..]"
Diego Magdaleno