java - resumen - modo de produccion primitivo caracteristicas
¿Por qué volver nulo para un trabajo primitivo en este caso? (3)
Este pedazo de código feo se compila pero lanza NPE si s == null
public static boolean isNullOrEmpty(String s)
{
return s != null ? s.isEmpty() : null;
}
mientras que esto no lo hace (como se esperaba):
public static boolean isNullOrEmpty(String s)
{
if(s != null)
return s.isEmpty();
else
return null;
}
Sé que ambos están claramente equivocados, pero cuando encontré el primer fragmento de código en nuestras fuentes, me sorprendió bastante que se compilara.
Edición: Aquí está la parte relevante del JLS de Java 7. Supuse que la primera afirmación se aplicaría pero la negrita sí.
15.25 ¿Operador condicional? :
[...]
El tipo de una expresión condicional se determina de la siguiente manera:
[...]
- Si uno de los operandos segundo y tercero es de tipo primitivo T, y el tipo del otro es el resultado de aplicar la conversión de boxeo (§5.1.7) a T, entonces el tipo de la expresión condicional es T.
[...]
- De lo contrario, el segundo y tercer operandos son de los tipos S1 y S2, respectivamente. Deje que T1 sea el tipo que resulta de aplicar la conversión de boxeo a S1 y que T2 sea el tipo que resulta de aplicar la conversión de boxeo a S2. El tipo de expresión condicional es el resultado de aplicar la conversión de captura (§5.1.10) a lub (T1, T2) (§15.12.2.7).
El Operador Ternario necesita encontrar el tipo de retorno más apropiado para ambos operandos.
Por lo tanto, permite un cierto "pulido" del tipo de retorno.
Como se muestra en su primer fragmento de código:
public static boolean isNullOrEmpty(String s)
{
return s != null ? s.isEmpty() : null;
}
s.empty()
devuelve boolean
primitivo mientras que el tercer operando devuelve null
. Así que el tipo de retorno común más específico es Boolean
. El trabajo del compilador es como reemplazar la línea por:
return s != null ? s.isEmpty() : (Boolean)null;
El método de tipo de retorno espera una primitiva boolean
, por lo que el compilador dice: "Genial, ¡solo tengo que desempaquetar mi resultado!". Desafortunadamente, null
no es unboxable y lleva a una NPE fea.
Con tu segundo fragmento:
public static boolean isNullOrEmpty(String s)
{
if(s != null)
return s.isEmpty();
else
return null;
}
No se realiza un "pulido" adicional del tipo de devolución previa ya que el compilador no vincula ambas declaraciones de retorno en este código => puede ser un trabajo demasiado difícil para él.
Entonces, en este caso, es lógico que el código ni siquiera se compile, ya que null
NO está asociado a Boolean
! Por lo tanto, no se produce ningún tipo de reparto.
Para compilarlo, debe escribirse como:
public static boolean isNullOrEmpty(String s)
{
if(s != null)
return s.isEmpty();
else
return (Boolean)null;
}
Pero no evita que ocurra la famosa NPE al intentar desempaquetar;)
Similar a Tricky Ternary Operator en JAVA
El operador ternario realiza Autoboxing utilizando las reglas citadas en JLS:
Esta regla es necesaria porque el operador condicional (§15.25) aplica la conversión de boxeo a los tipos de sus operandos y utiliza el resultado en otros cálculos.
El problema es con el Autoboxing en Java. El problema se debe a que el segundo operando no es tridimensional.
public static boolean isNullOrEmpty(String s)
{
return s != null ? null : null;
}
Este código no compilará
El primero tiene un operador de trincheras que tiene un tipo de resultado Boolean
. El NPE está convirtiendo un null
a un boolean
.
En realidad es algo como:
Boolean temp = s != null ? s.isEmpty() : null; //no problems here
return temp; //crash when temp==null
El segundo es intentar devolver un tipo incorrecto (Objeto en lugar de primitivo) y, por lo tanto, no se compila.