the - Java-operador ternario comportamiento extraño
ternary operator php (4)
Estaba tratando de quitar la parte fractional
de un double
en caso de que esté usando todo:
(d % 1) == 0 ? d.intValue() : d
Y encontré el siguiente comportamiento que no entiendo:
public static void main(String[] args) {
Double d = 5D;
System.out.println((d % 1) == 0); // true
System.out.println((d % 1) == 0 ? d.intValue() : "not whole"); // 5
System.out.println((d % 1) == 0 ? d.intValue() : d); // 5.0
}
Como puede ver en la tercera línea, el operador elige el valor else
- 5.0
aunque se cumpla la condición (d % 1) == 0
.
¿Que está pasando aqui?
El tipo de retorno del operador condicional ternario debe ser tal que se le puedan asignar los operandos segundo y tercero.
Por lo tanto, en su segundo caso, el tipo de retorno del operador es Object
(ya que tanto d.intValue()
como "not whole"
deben ser asignables a él), mientras que en el tercer caso es Double
(ya que ambos d.intValue()
d
debe ser asignable a ella).
Imprimir un Object
cuyo tiempo de ejecución es Integer
le da 5
mientras que imprimir un Double
le da 5.0
.
El tipo de una expresión a ? b : c
a ? b : c
es siempre el mismo que c
o el padre común más cercano de b
y c
.
System.out.println((d % 1) == 0 ? d.intValue() : "not whole"); // Comparable a parent of Integer and String
System.out.println((d % 1) == 0 ? d.intValue() : d); // Double is a widened int
Por cierto, d % 1
solo comprobará que no sea un todo, no que sea lo suficientemente pequeño como para que quepa en un valor int
. Una comprobación más segura es ver si el valor es el mismo cuando se convierte a int
o en long
double d = 5.0;
if ((long) d == d)
System.out.println((long) d);
else
System.out.println(d);
o puede evitar que se amplíe la espalda long
a un doble con
double d = 5.0;
System.out.println((long) d == d ? Long.toString((long) d) : Double.toString(d));
En su caso, los argumentos segundo y tercero del operador ternery son los tipos "int" y "Doble". Java debe convertir estos valores al mismo tipo para que se puedan devolver desde el operador ternario. Las reglas para hacer esto se dan en la especificación del lenguaje Java. https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25
En su caso, estas reglas resultan en la conversión de ambos parámetros al tipo "doble" (el "Doble" no está en la caja, el int se convierte en valor).
La solución es enviar los argumentos al operador ternario para que sean del mismo tipo (puede haber más corchetes en el siguiente lugar que los estrictamente necesarios, estoy un poco oxidado en las reglas de precedencia del operador Java).
System.out.println((d % 1) == 0 ? ((Number)(d.intValue())) : (Number)d);
Se elige correctamente. Luego lo envuelve en doble. Estos son 3 puntos clave:
Si el segundo y tercer operandos tienen el mismo tipo, ese es el tipo de la expresión condicional. En otras palabras, puede evitar todo el lío evitando los cálculos de tipo mixto.
Si uno de los operandos es del tipo T, donde T es byte, short o char y el otro es una expresión constante del tipo int cuyo valor es representable en el tipo T, el tipo de la expresión condicional es T.
De lo contrario, la promoción numérica binaria se aplica a los tipos de operandos, y el tipo de expresión condicional es el tipo promovido de los operandos segundo y tercero.