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

Неожиданный тип, полученный от тройного оператора

Я пытаюсь написать метод, который получает 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(). Кажется, что эти методы должны выполнять ту же работу. Но что я сделал не так?

4b9b3361

Ответ 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 достаточно мала, чтобы решить проблему с целыми числами, закодированными в формате с плавающей запятой.

Я написал код из памяти, но я думаю, что идея, стоящая за этим, понятна.