Java - ternary operator weird behaviour

我只是一个虾纸丫 提交于 2019-11-29 11:00:31

问题


I was trying to remove the fractional part from a double in case it is whole using:

(d % 1) == 0 ? d.intValue() : d

And encountered the following behavior which i don't understand:

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
}

As you can see on the third line, the operator chooses the else value - 5.0 even though the condition (d % 1) == 0 is met.

What's going on here?


回答1:


The return type of the ternary conditional operator must be such that both the 2nd and 3rd operands can be assigned to it.

Therefore, in your second case, the return type of the operator is Object (since both d.intValue() and "not whole" must be assignable to it) while in the third case it is Double (since both d.intValue() and d must be assignable to it).

Printing an Object whose runtime type is Integer gives you 5 while printing a Double gives you 5.0.




回答2:


The type of an expression a ? b : c is always the same as c or the closest common parent of b and 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

BTW d % 1 will only check it is a whole not, not that it's small enough to fit in anint value. A safer check is to see if the value is the same when cast to an int or long

double d = 5.0;
if ((long) d == d)
    System.out.println((long) d);
else
    System.out.println(d);

or you can prevent it widening the long back to a double with

double d = 5.0;
System.out.println((long) d == d ? Long.toString((long) d) : Double.toString(d));



回答3:


It chooses correctly. Then it wraps it in double. These are 3 key points:

  1. If the second and third operands have the same type, that is the type of the conditional expression. In other words, you can avoid the whole mess by steering clear of mixed-type computation.

  2. If one of the operands is of type T where T is byte , short , or char and the other operand is a constant expression of type int whose value is representable in type T, the type of the conditional expression is T.

  3. Otherwise, binary numeric promotion is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands.




回答4:


In your case the second and third arguments of the ternery operator are types "int" and "Double". Java must convert these values to the same type so they can be returned from the ternary operator. The rules for doing this are given in the Java language specification. https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25

In your case these rules result in the conversion of both parameters to type "double" (the "Double" is unboxed, the int is value-converted).

The fix is to cast the arguments to the ternary operator so that they are of the same type (there may be more brackets in the below than strictly needed, i'm a bit rusty on java operator precedence rules).

System.out.println((d % 1) == 0 ? ((Number)(d.intValue())) : (Number)d); 


来源:https://stackoverflow.com/questions/36245411/java-ternary-operator-weird-behaviour

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!