Extraño comportamiento ternario de Java al asignar valor. ¿Qué está haciendo Java detrás de escena para que esto suceda?

10

Hace unos días, me encontré con un escenario fascinante en el que no pude encontrar ninguna documentación sobre cómo o por qué Java permite que suceda lo siguiente. (Este fragmento es solo una forma simplificada del error).

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

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

en el fragmento de arriba:

si bool = true, obtienes el valor '5';

pero si bool = false, se obtiene una excepción de puntero nulo al intentar evaluar la operación ternaria. NO la declaración impresa.


Para solucionar esto, simplemente cambio 'resultado' a

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

Al hacer esto, obtendré el comportamiento esperado que necesitaba:

si bool = true, obtienes el valor '5';

pero si bool = false, entonces obtienes 'nulo'


ahora la parte divertida es que si divide esto en una declaración if / else normal, entonces Java NO le permite compilar

longVal = intVal; 

pero no capta eso a través del operador ternario. Entonces, ¿qué está haciendo Java para que sea un punto nulo en el fragmento original?

(Java 11)

Tim Z.
fuente

Respuestas:

10

Cuando haces esto:

Long result = bool ? intVal : longVal

Esta expresión está devolviendo ay long, cuando booles falsa, trata de desempaquetar nulla un valor largo para ajustar la resultvariable y arroja un NPE.

Cuando haces esto:

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

Esta expresión ya está regresando, Longentonces no hay necesidad de unboxing y el nullvalor se asigna con éxito a la resultvariable.

Referencia:

Como se discutió en la sección de comentarios, para comprender mejor por qué sucede esto, consulte las siguientes secciones del JLS:

Diego Magdaleno
fuente
Me sorprende que la tabla de referencia 15.25 A a E sea diferente cuando está "claro" que Integer / Long da como resultado un bnp (Integer, Long).
mate
Buena respuesta. En general, cuando no tengo ni idea de lo que ocurre dentro, recomiendo echar un vistazo al código de bytes compilado, que revela casi exactamente lo que se describe. Al menos al extraer un fragmento de código mínimo, eso es más o menos una cuestión de capacitación, cómo leerlo y comprenderlo.
Ene
Como JLS, la Sección 5.6.2 dice: "Si algún operando es de un tipo de referencia, está sujeto a la conversión de unboxing"; luego se aplica "Ampliación de la conversión primitiva (§5.1.2) [..]"
Diego Magdaleno