由三元运算符产生的意外types

我试图写一个方法得到一个double ,validation数字是否有点后面的东西,如果它返回一个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()发生。 看来这些方法必须做同样的工作。 但是我做错了什么?

正如其他答案所述,这种行为是因为三元expression式的可能结果必须具有相同的types。

因此,为了使三元版本的工作方式与convert1()int转换为Object相同,您需要做的就是:

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

您看到的效果与此问题中的效果类似。

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

具体来说, 标准说 :

条件expression式的types如下确定:

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

否则,对操作数types应用二进制数字提升(第5.6.2节),并且条件expression式的types是第二个和第三个操作数的提升types。

翻到标准页面, 我们看到 :

如果其中一个操作数的types是double,另一个则转换为double。

这是在这里发生的事情,然后是自动复制到一个Doubleif语句似乎没有发生这种转换,解释了这种差异。

更广泛地说—这不是一个好主意。 我不认为这是一个好的devise来返回一个int或一个double取决于值 – 如果你想四舍五入,使用Math.floor ,如果你不想打印小数,使用printf

编辑:我不认为这是一个好主意做hacky的东西来规避数字转换系统。 这是一个想法,直接给你一个String ,这似乎是你想要的:

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

三元运算符要求两个结果值是相同的types,所以int进行自动(安全)加宽转换,以使其double

三元和“等值”不完全一样。

用点号后的数字来解决问题:

 public Object convert(double number){ double whole = Math.floor(number); if(Math.abs(whole - number) < DELTA){ return (int) number; } return number; } 

DELTA是足够小的常量,用浮点格式编码整数来解决这个问题。

我从内存中编写代码,但是我认为它背后的想法很明显。