小坑大错之DecimalFormat采坑日记

引言

在最近的开发中,用到了DecimalFormat这个类来做精度控制的功能。比如想保留两位精度,代码如下:

        DecimalFormat decimalFormat = new DecimalFormat("0.##");
        decimalFormat.format(12345.2323)

        输出结果为:12345.23

掉坑与填坑

使用#和0的区别

对于使用数字"0"格式化,和使用“#”格式化在DecimalFormat中的区别在于:

  • "#" 表示有”有效“数字才显示。而使用数字 "0" 则表示在位数不足时或者"无效"时用"0"值补位。

这里的有效和无效指的是数学意义上的有效值。比如0010.2300,有效值为10.23,无效值为千位和百位的0,以及小数点第三位和第四位的0

看以下例子:

        DecimalFormat decimalFormat1 = new DecimalFormat("#.##");
        DecimalFormat decimalFormat2 = new DecimalFormat("0.00");
        System.out.println(decimalFormat1.format(45.2));
        System.out.println(decimalFormat1.format(45.20));
        System.out.println(decimalFormat2.format(45.2));
        System.out.println(decimalFormat2.format(45.20));

        System.out.println("******************整数部分测试********************");

        DecimalFormat decimalFormat3 = new DecimalFormat("####.00");
        DecimalFormat decimalFormat4 = new DecimalFormat("0000.00");
        System.out.println(decimalFormat3.format(0.20));
        System.out.println(decimalFormat3.format(10.20));
        System.out.println(decimalFormat4.format(0.20));
        System.out.println(decimalFormat4.format(10.20));
        
        输出为:
        ******************小数部分测试********************
        45.2
        45.2
        45.20
        45.20
        ******************整数部分测试********************
        .20
        10.20
        0000.20
        0010.20
使用除0和#以外的格式符号

对于某些特殊符号,比如“%”会对整体乘以100。或者有时候我们可能需要对格式化后的数据带上前缀或者后缀,比如如果说需求要求格式化的代码如下所示:

        DecimalFormat decimalFormat1 = new DecimalFormat("#.##%");
        DecimalFormat decimalFormat2 = new DecimalFormat("a0.00");
        DecimalFormat decimalFormat3 = new DecimalFormat("负数-0.0");
        DecimalFormat decimalFormat4 = new DecimalFormat("上午(0.0am0)");

对于这种情况(不要问我怎么有这种需求),会筛选除“0”和“#”进行格式化,并在整数前面加上前缀,小数后面带后缀,比如上面的输出结果如下所示:

        System.out.println(decimalFormat1.format(12.222));
        System.out.println(decimalFormat2.format(12.222));
        System.out.println(decimalFormat3.format(12.222));
        System.out.println(decimalFormat4.format(12.222));
        输出结果:
        1222.2%
        a12.22
        负数-12.2
        上午(12.22am)
格式化后转换成数值问题

这种问题分两种情况

  • 带分隔符的格式化后的数据转换问题
  • 语言环境格式化差异带来的数据转换问题

第一种情况比较有可预见性,比如以下代码:

        DecimalFormat decimalFormat = new DecimalFormat(",###.##");
        //报java.lang.NumberFormatException
        Double.valueOf(decimalFormat1.format(12345.2323));

原因是因为格式化的数据变成了“12,345.23”,所以会抛出NumberFormatException。这种情况一般情况下都能考虑到,但是第二种情况就有点坑爹了。看以下代码:

        DecimalFormat decimalFormat = new DecimalFormat("#.##");
        decimalFormat.format(12345.2323)

就是开头最简单的例子,在中文和英文环境会输出我们预计的结果“12345.23”。

但是!!,在譬如德语等环境下,会输出“12345,23”。原因是因为德语环境下的逗号和点号分隔符的作用是完全相反的。所以如果接下来我们使用了”Double.valueOf()“等转换操作,将会爆出NumberFormatException异常。通过查看DecimalFormat的构造方法:

    public DecimalFormat(String pattern) {
        // Always applyPattern after the symbols are set
        this.symbols = DecimalFormatSymbols.getInstance(Locale.getDefault(Locale.Category.FORMAT));
        applyPattern(pattern, false);
    }

默认是使用当前语言环境作为格式化的符号,因此我们可以手动设置格式化的符号,例如:

DecimalFormat.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.US));

但是强制使用某种语言环境下的格式化的符号是不可取的,程序中应该针对不同语言环境做不同处理。

你可能感兴趣的:(小坑大错之DecimalFormat采坑日记)