Comportement ternaire étrange de Java lors de l'attribution d'une valeur. Que fait Java dans les coulisses pour que cela se produise?

10

Il y a quelques jours, je suis tombé sur un scénario fascinant où je n'ai trouvé aucune documentation sur comment ou pourquoi Java laisse les choses se produire. (Cet extrait n'est qu'une forme simplifiée du bogue.)

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

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

dans l'extrait ci-dessus:

si le bool = true, alors vous obtenez la valeur '5';

mais si bool = false, vous obtenez une exception de pointeur nul lorsque vous essayez d'évaluer l'opération ternaire. PAS la déclaration imprimée.


Pour résoudre ce problème, je change simplement «résultat» en

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

Faire cela donnera le comportement attendu dont j'avais besoin:

si le bool = true, alors vous obtenez la valeur '5';

mais si bool = false, alors vous obtenez 'null'


maintenant la partie amusante est que si vous le divisez en une instruction if / else normale, alors java ne vous permet PAS de compiler

longVal = intVal; 

mais il n'attrape pas cela via l'opérateur ternaire. Alors, que fait Java pour en faire un point nul dans l'extrait d'origine?

(java 11)

Tim Z.
la source

Réponses:

10

Lorsque vous faites cela:

Long result = bool ? intVal : longVal

Cette expression renvoie un longet, lorsqu'elle boolest fausse, elle essaie de décompresser nullune valeur Long pour s'adapter à la resultvariable et lance un NPE.

Lorsque vous faites cela:

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

Cette expression est déjà de retour Longalors il n'est pas nécessaire de décompresser et la nullvaleur est correctement affectée à la resultvariable.

Référence:

Comme indiqué dans la section des commentaires, pour mieux comprendre pourquoi cela se produit, consultez les sections suivantes du JLS:

Diego Magdaleno
la source
Je suis surpris que vous vous référiez au tableau de référence 15.25 A à E où il est "clair" que Integer / Long aboutit à un bnp (Integer, Long).
mat
Bonne réponse. Généralement, lorsque je n'ai absolument aucune idée de ce qui se passe à l'intérieur, je recommande de consulter le bytecode compilé, qui révèle presque exactement ce qui est décrit. Au moins lors de l'extraction d'un extrait de code minimal, c'est plus ou moins une question de formation, de lecture et de compréhension.
Jan Held
Comme le dit le JLS, la section 5.6.2 : "Si un opérande est de type référence, il est soumis à une conversion de déballage"; puis "L'élargissement de la conversion primitive (§5.1.2) est appliqué [..]"
Diego Magdaleno