BigDecimal的正确打开方式

前言

项目中明确规定,凡是涉及到金额的属性定义都必须使用BigDecimal类型,这里来和大家一起学习下BigDecimal的正确打开方式。

先来个错误的示范

话不多说,直接上demo

    @Test
    public void wrongUseDecimal() {
        BigDecimal test1 = new BigDecimal(1.745);
        BigDecimal test2 = new BigDecimal(0.745);
        test1 = test1.setScale(2, BigDecimal.ROUND_HALF_UP);
        test2 = test2.setScale(2, BigDecimal.ROUND_HALF_UP);
        System.out.println(test1);
        System.out.println(test2);
    }

上面是对1.745和0.745四舍五入保留两位有效数字,输出结果如下

1.75
0.74

使用参数为float或double的BigDecimal创建对象会丢失精度。

System.out.println(new BigDecimal(1.745)); 
// 1.74500000000000010658141036401502788066864013671875
System.out.println(new BigDecimal(0.745)); 
// 0.74499999999999999555910790149937383830547332763671875

如上面所示,因为精度丢失,所以在四舍五入的时候没有达到预期目标。大家不要觉得不就相差0.01么,影响不大吧,但是如果这两个数字后面的单位是亿呢?因此强烈建议不要使用参数为float或double的BigDecimal创建对象。

正确使用姿势

//使用BigDecimal(String val)的构造方法创建对象
new BigDecimal("1.745");
new BigDecimal("0.745");
//使用BigDecimal的valueOf(double val)方法创建对象
BigDecimal.valueOf(1.745);
BigDecimal.valueOf(0.745);

其实BigDecimal.valueOf也是将浮点类型转换成字符串类型之后再创建BigDecimal对象的

public static BigDecimal valueOf(double val) {
    // Reminder: a zero double returns '0.0', so we cannot fastpath
    // to use the constant ZERO.  This might be important enough to
    // justify a factory approach, a cache, or a few private
    // constants, later.
    return new BigDecimal(Double.toString(val));
}

拓展DecimalFormat

DecimalFormat 是 NumberFormat 的一个具体子类,用于格式化十进制数字。该类设计有各种功能,使其能够解析和格式化任意语言环境中的数,包括对西方语言、阿拉伯语和印度语数字的支持。它还支持不同类型的数,包括整数 (123)、定点数 (123.4)、科学记数法表示的数 (1.23E4)、百分数 (12%) 和金额 ($123)。所有这些内容都可以本地化。

符号位置本地化?含义
0数字阿拉伯数字
#数字阿拉伯数字如果不存在就显示为空
.数字小数分隔符或货币小数分隔符
-数字减号
,数字分组分隔符
E数字分割科学技术法中的尾数和指数。在前缀和后缀中无需添加引号
;子模式边界分隔正数和负数子模式
%前缀或后缀乘以100并显示为百分数
/u2030前缀或后缀乘以1000并显示为千分数
¤ (\u00A4)前缀或后缀货币记号,由货币符号替换。如果两个同时出现,则用国际货币符号替换。如果出现在某个模式中,则使用货币小数分隔符,而不使用小数分隔符
'前缀或后缀用于在前缀或或后缀中为特殊字符加引号,例如 "'#'#" 将 123 格式化为 "#123"。要创建单引号本身,请连续使用两个单引号:"# o''clock"

测试Demo如下

double pi = 3.1415927;//圆周率
//取一位整数
System.out.println(new DecimalFormat("0").format(pi));//3
//取一位整数和两位小数
System.out.println(new DecimalFormat("0.00").format(pi));//3.14
//取两位整数和三位小数,整数不足部分以0填补。
System.out.println(new DecimalFormat("00.000").format(pi));// 03.142
//取所有整数部分
System.out.println(new DecimalFormat("#").format(pi));//3
//以百分比方式计数,并取两位小数
System.out.println(new DecimalFormat("#.##%").format(pi));//314.16%

BigDecimal的等值比较

BigDecimal大小,想必大家不会用>和<来进行大小比较吧,看看下面的demo

BigDecimal bd1 = new BigDecimal("1.0");
BigDecimal bd2 = new BigDecimal("1.00");
System.out.println(bd1.equals(bd2));  //false
System.out.println(bd1.compareTo(bd2)); //0

上面的运行结果,其实归结于BigDecimal中的equals方法的实现会比较两个数字的精度,而compareTo方法则只会比较数值的大小。这些小知识日常开发中要多注意,写代码最怕太自信,如果经验不足,还是自己多测测。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值