Java 三元运算符导致的意外类型

Java 三元运算符导致的意外类型,java,ternary-operator,Java,Ternary Operator,我正在尝试编写一个方法,该方法获取一个double,验证数字是否在点后面,如果返回double,如果不返回int public class Solution { public static void main(String[] args) { double d = 3.000000000; System.out.println(convert1(d)); System.out.println(convert2(d)); }

我正在尝试编写一个方法,该方法获取一个
double
,验证数字是否在点后面,如果返回
double
,如果不返回
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()
中。看来这些方法必须做同样的工作。但是我做错了什么?

三元运算符要求两个结果值的类型相同,因此
int
将自动(安全)加宽转换为
double


三元函数与它的
if
“等价物”并不完全相同。

您看到的效果与类似

Java使用三元运算符处理类型的方式与使用
if
语句处理类型的方式略有不同

具体而言,委员会:

条件表达式的类型确定如下:

否则,如果第二个和第三个操作数的类型为 可转换(§5.1.8)为数字类型,则有几种情况:

否则,二进制数字提升(§5.6.2)适用于 操作数类型,条件表达式的类型为 第二个和第三个操作数的升级类型

翻到标准的那一页:

如果其中一个操作数的类型为double,则另一个操作数将转换为double

这就是这里发生的事情,然后自动装箱到一个
Double
。在解释差异的
if
语句中,似乎没有发生这种转换

更广泛地说,这不是一个好主意。我认为根据值返回
int
double
中的一个不是一个好的设计——如果您想舍入某个值,请使用
Math.floor
,如果您不想打印小数,请使用
printf

编辑:我不认为这是一个好主意做黑客的事情,以绕过常规的数字转换系统。这里有一个想法可以直接为您提供一个
字符串
,它似乎就是您想要的:

static String convert3(double d) {
    return ((d % 1 == 0) ? Integer.toString((int)d) : Double.toString(d));
}

正如其他答案所述,这种行为是因为三元表达式的两个可能结果必须具有相同的类型

因此,要使三元版本与
convert1()
的工作方式相同,只需将
int
强制转换为
对象

static Object convert2(double d) {
    return ((d % 1) == 0) ? ((Object) (int) (d)) : d;
}

要解决点后数字的问题,请执行以下操作:

public Object convert(double number){
  double whole = Math.floor(number);
  if(Math.abs(whole - number) < DELTA){
    return (int) number;
  }
  return number;
}
公共对象转换(双倍数字){
双整数=数学楼层(数字);
if(数学绝对值(整数)
DELTA
是足够小的常量,可以解决浮点格式编码的整数的问题


我已经根据记忆编写了代码,但我认为背后的想法很清楚。

谢谢您提供了非常详细的答案。我需要这个GUI方法,因此我既不能使用Mats.floor也不能使用printf。@user3922109您的用例是什么?转换为两种不同的数字类型中的一种几乎肯定不是可行的方法。您需要的字符串是带小数还是不带小数?@user3922109我在一个示例中添加了将其直接转换为
字符串
,这似乎正是您所需要的。+1表示
这不是一个好主意。我不认为根据值返回int或double中的一个是好的设计-这是我看到OP时想到的第一件事example@vaxquis是的,OP似乎极有可能再次(再次)受到数字促销规则的影响。如果他需要一个字符串,他应该使用一个字符串。完全脱离了这个问题的主题,但您是否知道,由于浮点不准确,几乎所有表示为双精度的整数都将是该整数值?也就是说,我希望你会经常得到
x.0
,而你却没有想到。这个运算符实际上被称为条件运算符,如@Patrick Collins@Heuster的回答所示。这是一个常见的误解。实际上,许多整数值精确地转换为双精度。尤其是绝对值低于2^53 IIRC的所有,这比所有32位整数都多。只有经过一些转换或某些类型的操作后,才会失去精度。(加法、减法和范围内乘法都可以。)@MichaelAnderson:任何双精度运算要么足够小,如果它是一个整数,就会非常精确;要么太大,以至于精度不会超过小数点。注意,丢失大浮点数的精度不能使其成为非整数。(是的,极限是2^53)。@MichealAnderson好的,也许我的措辞有点太强了,这不仅仅发生在整数运算中。但是,由于这里的问题是看一个数字是否为整数,我们可以安全地假设OP不限于整数。例如,这个问题肯定会发生在
10*0.1
上。你可以做得稍微好一点,并将其转换为
数字,对吗?@Chris:是的,我只是演示了机制如何使其与
convert1()
相同,后者返回
对象。对于这样的方法,
Number
String
可能是更符合逻辑的返回值。