Java BigDecimal类型的使用和注意点

一、前言

在这里插入图片描述
在金融相关的项目中,BigDecimal类被广泛用于精确的数值、金额的计算。记录如何使用以及在使用BigDecimal的过程中,存在的要注意的几个坑。

二、BigDecimal四则运算

2.1 加法

add()函数

2.2 减法

subtract()函数

2.3 乘法

multiply()函数

2.4 除法

divide()函数

2.5 绝对值

abs()函数

三、注意点

3.1 浮点数初始化

BigDecimal problematic = new BigDecimal(0.1);
System.out.println("Problematic: " + problematic.toString());
 
//输出 Problematic: 
0.1000000000000000055511151231257827021181583404541015625

直接使用new BigDecimal(double)构造方法会精度缺失。
正例:

BigDecimal problematic1 =  BigDecimal.valueOf(0.1);
BigDecimal problematic2 =  new BigDecimal("0.1");
System.out.println("Problematic: " + problematic1.toString());
System.out.println("Problematic: " + problematic2.toString());

//输出
Problematic: 0.1
Problematic: 0.1

3.2 比较数值时使用compareTo()方法而非equals()

BigDecimal bd1 = new BigDecimal("0.10");
BigDecimal bd2 = new BigDecimal("0.1");
System.out.println(bd1.equals(bd2)); // 输出: false
System.out.println(bd1.compareTo(bd2) == 0); // 输出: true

BigDecimal的equals方法不仅比较数值,还会比较对象的scale(小数点后的位数),如果只想比较数值,而不考虑scale,应该使用compareTo方法。源码中:
在这里插入图片描述

3.3 做除法时,未指定精度可能异常

BigDecimal dividend = new BigDecimal("10");
BigDecimal divisor = new BigDecimal("3");
BigDecimal result = dividend.divide(divisor); // 未指定精度和舍入模式
System.out.println(result);


//输出
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
 at java.math.BigDecimal.divide(BigDecimal.java:1693)
 at com.example.demo.controller.Test.main(Test.java:26)

未指定精度和舍入模式,会抛出ArithmeticException异常。
正例:

// 设置精度为2位,并按照四舍五入的规则进行舍入
BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP);

3.4 BigDecimal转String,科学计数法展示问题

System.out.println( new BigDecimal("0.0000000000001").toString());
BigDecimal bigDecimal = new BigDecimal("1E+12");
System.out.println(bigDecimal.toString());
//输出 1E-13
//输出 1E+12

原因是 toString() 某些场景下会使用科学计数法展示。
如果不想用任何计数法,可以使用 toPlainString()。

System.out.println( new BigDecimal("0.0000000000001").toPlainString());
BigDecimal bigDecimal = new BigDecimal("1E+12");
System.out.println(bigDecimal.toPlainString());
//输出 
0.0000000000001
1000000000000

3.5 注意使用setScale方法设置精度

BigDecimal的精度是无限的,因此一般在计算的时候,要注意设置精度几位。

BigDecimal number = new BigDecimal("123.4567");
BigDecimal roundedNumber = number.setScale(2, RoundingMode.HALF_UP);
//输出
123.46

RoundingMode.HALF_UP 是一种舍入模式,用于四舍五入。除了HALF_UP之外,还有几个常用的舍入模式:

UP:远离零方向舍入的舍入模式。总是在非零舍弃部分之前增加数字。
DOWN:接近零方向舍入的舍入模式。总是在非零舍弃部分之前减少数字。
CEILING:接近正无穷大的方向舍入的舍入模式。如果BigDecimal是正的,则舍入行为与UP相同;如果是负的,则舍入行为与DOWN相同。
FLOOR:接近负无穷大的方向舍入的舍入模式。如果BigDecimal是正的,则舍入行为与DOWN相同;如果是负的,则舍入行为与UP相同。
HALF_DOWN:向“最近邻居”舍入,除非两边距离相等,此时向下舍入。
HALF_EVEN:向“最近邻居”舍入,除非两边距离相等,此时向偶数舍入。这种模式也称为“银行家舍入法”,因为它减少了累计错误。

最后,使用setScale方法生成新的BigDecimal实例,并不会更改原有对象。所以使用
用setScale调整数字精度后,别忘把新生成的对象赋值回原来的变量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

容若只如初见

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值