Java三元运算符无法工作?

3
假设我们有一个StringBuilder和一个double。现在想要将这个double添加到StringBuilder中。如果这个double可以表示为整数(例如3.0,5.0等),我希望将其添加为整数,否则添加为double。
实现这个功能的第一种方法是:
StringBuilder sb = new StringBuilder();
double d = 3.5;

if (d % 1 == 0) sb.append((int) d);
else sb.append(d);

System.out.println(sb.toString());

d3.0 时,这仍然有效,将附加 3;如果 d3.5,则会附加 3.5。

现在我想用三元运算符简洁地实现这个:

StringBuilder sb = new StringBuilder();
double d = 3.5;

sb.append(d % 1 == 0 ? (int) d : d);

System.out.println(sb.toString());

现在我有一个问题,每次如果double是3.03.5,它都会被添加为双精度浮点数!只有当我在truefalse上进行理论转换时才有效...但是每次都是这样,这不是我想要的。问题出在哪里?为什么三元运算符不起作用?


1
你应该使用DecimalFormat("0.#")来消除尾随的零,而不是强制转换为int - Mick Mnemonic
6个回答

5
这种行为在JLS-15.25中有记录。条件运算符?: :

如果操作数之一是类型T,其中T是byte、short或char,而另一个操作数是类型int的常量表达式(§15.28),其值可以用类型T表示,则条件表达式的类型为T。

当您编写

(a > b) ? 'a' : 65

第二种类型转换为char。
阅读JLS,它解释了其他情况下的行为(相同的方法)。

很奇怪,如果我在Eclipse中评估d % 1 == 0 ? (int) d : d(其中d = 3),它会返回“3”。但是它会附加“3.0”。但这可能是Eclipse的问题。 - Steve Smith

2
这种行为的原因是三元运算符表达式有一个明确定义的类型。JLS详细描述了如何计算这个类型,但大体上来说,它是冒号前表达式的类型和冒号后表达式的类型的最小上界。
例如,如果b是布尔型,i是整型,d是双精度浮点型,则b ? i : d的类型为双精度浮点型,因为双精度浮点型是整型和双精度浮点型的最小上界。当你在StringBuilder上调用append( b ? i : d )时,你会得到带有双精度浮点型参数的append版本。在你的情况下也是同样的事情发生了,即d % 1 == 0 ? (int) d : d

1

当对原始数字使用三元运算符时,第二个和第三个操作数会受到二进制数值提升的影响。在您的情况下,int 被转换为 double。这在 JLS #15.25 中有明确规定。


1

StringBuilder.append()方法有多个重载,用于不同类型的参数。使用哪种方法重载是在编译时决定的。三元运算符的结果只有一个类型,要么是int,要么是double,在这种情况下是double

if语句中,编译器根据分支使用适当的append()方法重载。


0

我觉得编译器把 sb.append(d % 1 == 0 ? (int) d : d) 视为 sb.append(double),否则将把 sb.append((int) d) 视为 sb.append(int)


0

数字条件表达式是独立的表达式(§15.2)。

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

如果第二个和第三个操作数具有相同的类型,则该条件表达式的类型为该类型。

如果第二个和第三个操作数中的一个是原始类型T,而另一个操作数的类型是应用装箱转换(§5.1.7)到T的结果,则条件表达式的类型为T。

如果其中一个操作数是类型为byte或Byte,而另一个操作数是类型为short或Short,则条件表达式的类型为short。

如果其中一个操作数是类型为T(其中T为byte、short或char),而另一个操作数是类型为int的常量表达式(§15.28),其值可以表示为类型T,则条件表达式的类型为T。

如果其中一个操作数是类型为T,其中T为Byte、Short或Character,而另一个操作数是类型为int的常量表达式,其值可以表示为将拆箱转换应用于T的结果类型U,则条件表达式的类型为U。

否则,对操作数类型应用二进制数字提升(§5.6.2),条件表达式的类型是第二个和第三个操作数的提升类型。
类型转换为它们相应的基本类型,这称为取消装箱。 如果一个操作数是常量int(未在取消装箱之前为Integer),其值可以表示为另一种类型,则将int操作数转换为另一种类型。 否则,较小的类型将转换为下一个更大的类型,直到两个操作数具有相同的类型。 转换顺序如下:
byte -> short -> int -> long -> float -> double char -> int -> long -> float -> double 最终整个条件表达式获得其第二个和第三个操作数的类型。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接