美文网首页
小坑大错之DecimalFormat采坑日记

小坑大错之DecimalFormat采坑日记

作者: Swy2w | 来源:发表于2018-09-03 13:30 被阅读13次

    引言

    在最近的开发中,用到了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采坑日记

          本文链接:https://www.haomeiwen.com/subject/icsbwftx.html