Подтвердить что ты не робот

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.

Что здесь происходит?

4b9b3361

Ответ 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);