由三元运算符产生的意外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。
这是在这里发生的事情,然后是自动复制到一个Double
。 if
语句似乎没有发生这种转换,解释了这种差异。
更广泛地说—这不是一个好主意。 我不认为这是一个好的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
是足够小的常量,用浮点格式编码整数来解决这个问题。
我从内存中编写代码,但是我认为它背后的想法很明显。