产品需求:
要求客户端拿到服务器返回的数据后,以最多保留2位小数的形式展示该数据。例如:2.247==>2.25、2.20==>2.2。
拿到这个需求后,当然最先考虑的是使用String.format("%.2f", 2.20),可是结果却是:
很显然,String.format的形式只能适用于固定的小数保留需求。
之后笔者在网上搜索了一圈,发现主要有DecimalFormat、BigDecimal、NumberFormat这几种方案。鉴于它们的功能一样,本文就对DecimalFormat做一番研究。
1 DecimalFormat 中的 0 和 #
1 | import java.text.DecimalFormat; |
结论:
1、小数部分 #代表最多有几位,0代表必须有且只能有几位。
.00 表示最终结果有两位小数,没有则补0,多了就四舍五入第三个小数。
.## 表示最终结果最多有两位小数,一位或者没有都可以,多了同样四舍五入第三位。
2、整数部分 0 和 #。
当整数部分为0时,比如 0.1,# 此时认为整数部分不存在,所以不写 。0 认为没有至少也得一位,写上0。(这跟上面第一部分的表现是一致的:# 有就写,没有就不写;0 必须有,没有就补0。)
3、整数部分有多位时: 2;20;200。
由上面的结果可以看出 0和#对整数部分多位时的处理是一致的,就是有几位写多少位。(这跟上面两部分的表现是不一致的 在有多位时,0和#都没有匹配位数,而是有多少写多少。)
通常,我们使用的处理方式有: 0.00 或者 0.## 。
实践:
对于问题中的2.247==>2.25、2.20==>2.2,采用DecimalFormat实现如下:
1 | new DecimalFormat("0.##").format(dd); |
2 问题延伸
1、DecimalFormat对数值格式化的舍入问题——RoundingMode。
2、恶心的0.5四舍五入问题。
对于此条问题,笔者使用的方式是文中所提及的在具体数据后加上0.000001。
3、String.format对于浮点型数据的展示问题。
注意在精度要求高的情况下,String.format中使用的浮点数必须是双精度的,这样才能确保四舍五入的规则正确。比如:
1 | System.out.println(String.format("%.2f", 2.245f)); |
打印的结果是 2.24,错误。如果是这样:
1 | System.out.println(String.format("%.2f", 2.245)); |
打印的结果就是 2.25,正确。
为什么会这样呢?这里涉及到精度损耗的问题。在String.format("%.2f", 2.245f)中接受的数值应该是double类型的,所以2.245f 实际上是被转换为了double类型。而 java 将2.245f 强制转化为double类型后,得到的实际double类型值为:2.244999885559082。