Неожиданный тип, полученный от тройного оператора
Я пытаюсь написать метод, который получает double
, проверяет, имеет ли номер что-то после точки, а если он возвращает - возвращает double
, если doesn't-возвращает int
.
public class Solution {
public static void main(String[] args) {
double d = 3.000000000;
System.out.println(convert1(d));
System.out.println(convert2(d));
}
static Object convert1(double d) {
if(d % 1 == 0)
return (int) d;
else
return d;
}
static Object convert2(double d) {
return ((d%1) == 0) ? ((int) (d)) : d;
}
}
Вывод:
3
3.0
Итак, все, что я хочу, происходит в методе convert1()
, но не происходит в методе convert2()
. Кажется, что эти методы должны выполнять ту же работу. Но что я сделал не так?
Ответы
Ответ 1
Как указывали другие ответы, это поведение объясняется тем, что оба возможных результата тройного выражения должны иметь один и тот же тип.
Поэтому все, что вам нужно сделать, чтобы ваша тройная версия работала так же, как convert1()
, - это сделать int
на Object
:
static Object convert2(double d) {
return ((d % 1) == 0) ? ((Object) (int) (d)) : d;
}
Ответ 2
Вы видите эффект, похожий на тот, что в этом вопросе.
Немного разные правила определяют то, как Java обрабатывает типы с тернарным оператором, чем с оператором if
.
В частности, стандарт мы видим:
Если один из операндов имеет тип double, другой преобразуется в double.
что происходит здесь, за которым следует autoboxing до Double
. Похоже, что такое преобразование не происходит с оператором if
, объясняя разницу.
В более широком смысле - это не очень хорошая идея. Я не думаю, что хороший дизайн для возврата в один из int
или Double
в зависимости от значения - если вы хотите что-то отключить, используйте Math.floor
, и если вы не хотите печатать десятичные знаки, используйте printf
.
РЕДАКТИРОВАТЬ: Я не думаю, что это хорошая идея делать хакерские вещи, чтобы обходить обычную числовую систему преобразования. Вот идея, которая дает вам String
напрямую, что, как вам кажется, выглядит следующим образом:
static String convert3(double d) {
return ((d % 1 == 0) ? Integer.toString((int)d) : Double.toString(d));
}
Ответ 3
Тернарный оператор требует, чтобы оба значения результата были одного и того же типа, поэтому int
подвергается автоматическому (безопасному) расширению, отличному от double
.
Тернар не совсем то же, что его эквивалент if
.
Ответ 4
Чтобы решить проблему с числами после точки:
public Object convert(double number){
double whole = Math.floor(number);
if(Math.abs(whole - number) < DELTA){
return (int) number;
}
return number;
}
DELTA
достаточно мала, чтобы решить проблему с целыми числами, закодированными в формате с плавающей запятой.
Я написал код из памяти, но я думаю, что идея, стоящая за этим, понятна.