DecimalFormat使用详解

Catalogue
  1. 1 DecimalFormat 中的 0 和 #
  2. 2 问题延伸

产品需求:
要求客户端拿到服务器返回的数据后,以最多保留2位小数的形式展示该数据。例如:2.247==>2.25、2.20==>2.2。

拿到这个需求后,当然最先考虑的是使用String.format("%.2f", 2.20),可是结果却是:

很显然,String.format的形式只能适用于固定的小数保留需求。
之后笔者在网上搜索了一圈,发现主要有DecimalFormat、BigDecimal、NumberFormat这几种方案。鉴于它们的功能一样,本文就对DecimalFormat做一番研究。

1 DecimalFormat 中的 0 和 #

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import java.text.DecimalFormat;

public class DecimalFormatTest
{
public static void main(String[]args){
DecimalFormat df1,df2;
System.out.println("整数部分0/#的区别");

df1 = new DecimalFormat("#.00");
df2 = new DecimalFormat("0.00");

System.out.println(df1.format(0.1)); // .10
System.out.println(df2.format(0.1)); // 0.10

System.out.println("小数部分0/#的区别");

df1 = new DecimalFormat("0.00");
df2 = new DecimalFormat("0.##");

System.out.println(df1.format(0.1)); // 0.10
System.out.println(df2.format(0.1)); // 0.1

System.out.println(df1.format(0.006)); // 0.01
System.out.println(df2.format(0.006)); // 0.01

System.out.println("3、整数部分有多位");

df1 = new DecimalFormat("0.00");
df2 = new DecimalFormat("#.00");

System.out.println(df1.format(2)); // 2.00
System.out.println(df2.format(2)); // 2.00

System.out.println(df1.format(20)); // 20.00
System.out.println(df2.format(20)); // 20.00

System.out.println(df1.format(200)); // 200.00
System.out.println(df2.format(200)); // 200.00
}
}

结论:
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。