Java-троичное поведение оператора
Я пытался удалить часть fractional
из double
, если она целая, используя:
(d % 1) == 0 ? d.intValue() : d
И столкнулся с следующим поведением, которое я не понимаю:
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
}
Как вы можете видеть на третьей строке, оператор выбирает значение else
- 5.0
, даже если выполнено условие (d % 1) == 0
.
Что здесь происходит?
Ответы
Ответ 1
Возвращаемый тип тернарного условного оператора должен быть таким, чтобы ему могли быть присвоены как 2-й, так и 3-й операнды.
Поэтому во втором случае возвращаемый тип оператора Object
(поскольку для него должны быть назначены как d.intValue()
, так и "not whole"
), а в третьем случае это Double
(так как оба d.intValue()
и d
должны быть назначены ему).
Печать Object
, тип выполнения которой Integer
дает вам 5
при печати Double
дает вам 5.0
.
Ответ 2
Тип выражения a ? b : c
всегда совпадает с c
или ближайшим общим родителем b
и 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
будет проверять только целое, а не на то, что он достаточно мал, чтобы соответствовать значению int
. Более безопасная проверка заключается в том, чтобы увидеть, совпадает ли значение при нажатии на int
или long
double d = 5.0;
if ((long) d == d)
System.out.println((long) d);
else
System.out.println(d);
или вы можете предотвратить его расширение long
обратно в double с помощью
double d = 5.0;
System.out.println((long) d == d ? Long.toString((long) d) : Double.toString(d));
Ответ 3
Он выбирает правильно. Затем он обертывает его в два раза. Это 3 ключевых момента:
-
Если второй и третий операнды имеют один и тот же тип, это тип условного выражения. Другими словами, вы можете избежать всего беспорядка, избегая смешанных вычислений.
-
Если один из операндов имеет тип T, где T является байтом, коротким или char, а другой операндом является константное выражение типа int, значение которого представляется в типе T, тип условного выражение T.
-
В противном случае для типов операндов применяется двоичное числовое продвижение, а тип условного выражения - продвинутый тип второго и третьего операндов.
Ответ 4
В вашем случае вторым и третьим аргументами оператора ternery являются типы "int" и "Double". Java должен преобразовать эти значения в один и тот же тип, чтобы их можно было вернуть из тернарного оператора. Правила для этого приведены в спецификации языка Java. https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.25
В вашем случае эти правила приводят к преобразованию обоих параметров в тип "double" ( "Double" is unboxed, int преобразуется по значению).
Исправление состоит в том, чтобы отнести аргументы к тернарному оператору, чтобы они были одного типа (в нижнем случае может быть больше скобок, чем строго необходимо, я немного ржав по правилам приоритета java-оператора).
System.out.println((d % 1) == 0 ? ((Number)(d.intValue())) : (Number)d);