条件表达式的类型问题
条件表达式在编程中经常被用到,如 a=b?x:y 简单的一行语句,就能替换一个 if else 语句块,所以非常受欢迎。但在使用时,对条件表达式返回的类型需要留意,特别是在第二、第三运算符涉及到基本数据类型装箱、拆箱与数值类型提升时。
一、案例
下面一段代码想要执行的操作是:将系统的价格数字转换为通用的价格,如果showDecimal为true,显示小数点后的数字,否则不显示小数点。
private static void transPrice(long price, boolean showDecimal) { Float formatPrice = price/10000F; Object data = showDecimal ? formatPrice : formatPrice.intValue(); System.out.println(data.toString()); }
transPrice(135000, true); //期待输入结果: 13.5
transPrice(0, false); //期待结果: 0
调用该方法后,预期输出 0,实际得到 0.0。也即黑体字一行并未达到预期要的结果。反编译该段代码后,如下:
Object data = Float.valueOf(showDecimal?formatPrice.floatValue():(float)formatPrice.intValue());
看完这段代码后,我们大致可以知道出现该结果的原因,但是编译器为何会将这段代码这样处理呢?
二、案例分析
根据 Java 语言规范 jls-15.25 (JDK8)的描述
The process for determining the type of a conditional expression depends on the kind of conditional expression, as outlined in the following sections.
The following tables summarize the rules above by giving the type of a conditional expression for all possible types of its second and third operands. bnp(..) means to apply binary numeric promotion.
Table 15.25-A. Conditional expression type (Primitive 3rd operand, Part I)
3rd → byte
short
char
int
2nd ↓ float
bnp( float
,byte
)bnp( float
,short
)bnp( float
,char
)bnp( float
,int
)Float
bnp( Float
,byte
)bnp( Float
,short
)bnp( Float
,char
)bnp( Float
,int
)double
bnp( double
,byte
)bnp( double
,short
)bnp( double
,char
)bnp( double
,int
)
也就是说:当条件表达式的第二运算符是 Float 引用类型、第三运算符是 int 基本数据类型时,需要对第二、第三运算符进行双目数值类型提升(binary numeric promotion)。
该操作的结果是:
1.第二运算符是引用 Float 引用类型,对其进行拆箱操作,第二运算符调用 formatPrice.floatValue()
2.第二运算符现在是 float 类型,第三运算符是 int 类型,因此将第三运算符也转换成 float 类型,于是有 (float)formatPrice.intValue()
最后,在赋值给 data 时,需要将 float 类型的数据装箱为 Float.valueOf(...)
三、解决方案
使用 if else 语句
Float formatPrice = price/10000F; Object data; if (hasDecimal) {
priceNum = formatPrice; } else { priceNum = formatPrice.intValue(); }
这样,就保证了 int 不会被提升为 float 类型。
当然,本例稍微有点特殊。一般情况下使用条件表达式,只需要得到一个类型的结果。此处只是借此来分析条件表达式对于第二、第三运算符类型的处理。
参考文档:
JDK 8规范文档:http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.25