为什么不能用BigDecimal的equals方法做等值比较?

文章讲述了BigDecimal在Java中的使用,重点讲解了equals方法和compareTo方法在比较数值时的区别,强调了equals方法会同时考虑值和精度,而compareTo方法仅比较值。并提到了在金融场景下,尤其是《阿里巴巴Java开发手册》中的建议:对于BigDecimal的等值判断应使用compareTo,以避免精度问题。
摘要由CSDN通过智能技术生成

回答:

因为BigDecimal的equals方法和compareTo并不一样,equals方法会比较两部分内容,分别是值和精度,而对于0.1和0.10这两个数字,他们的值虽然一样,但是精度是不一样的,所以在使用equals比较的时候会返回false,即会比较值和小数点位是否相等。

扩展

BigDecimal,相信对于很多人来说都不陌生,很多人都知道他的用法,这是一种java.math包中提供的一种可以用来进行精确运算的类型。

很多人都知道,在进行金额表示、金额计算等场景,不能使用double、float等类型,而是要使用对精度支持的更好的BigDecimal。


所以,很多支付、电商、金融等业务中,BigDecimal的使用非常频繁。而且不得不说这是一个非常好用的类,其内部自带了很多方法,如加,减,乘,除等运算方法都是可以直接调用的。

除了需要用BigDecimal表示数字和进行数字运算以外,代码中还经常需要对于数字进行相等判断。
关于这个知识点,在最新版的《阿里巴巴Java开发手册》中也有说明:

10.【强制】如上所示BigDecimal的等值比较应使用compareTo()方法,而不是equals()方法。说明:equals方法会比较值和精度(1.0与1.00返回结果为false),而compareTo则会忽略精度。

BigDecimal的比较

上代码

if(bigDecimal == bigDecimal1){
    //两个数相等
}

上面存在着代码的低级错误,因为BigDecimal是对象,所以不能用==来判断两个数字的值是否相等。

但是再看一下以下的代码

BigDecimal bigDecimal = new BigDecimal(1);
BigDecimal bigDecimal1 = new BigDecimal(1);
System.out.println(bigDecimal.equals(bigDecimal1));

BigDecimal bigDecimal2 = new BigDecimal(1);
BigDecimal bigDecimal3 = new BigDecimal(1.0);
System.out.println(bigDecimal2.equals(bigDecimal3));

BigDecimal bigDecimal4 = new BigDecimal("1");
BigDecimal bigDecimal5 = new BigDecimal("1.0");
System.out.println(bigDecimal4.equals(bigDecimal5));

以上代码输出结果位

true
true
false

这里就涉及到BigDecimal中equals原理了,它会比较值和精度两部分,所以第一个和第三个为true和false, 但是为什么第二个精度不一样会是true呢?

这里又涉及到BigDecimal的标度问题了,这个问题其实比较复杂,这里简单写下:

首先, BigDecimal一共有四种构造方法:

BigDecimal(int)
BigDecimal(double)
BigDecimal(long)
BigDecimal(String)

以上四个方法创建出来的BigDecimal的精度(标度)是不同的。

为什么标度不同

BigDecimal(int) BigDecimal(long)

BigDecimal(int) BigDecimal(long) 因为都是整数,所以标度判定为0

public BigDecimal(int val){
    this.intCompact = val;
    this.scale = 0;
    this.intval null;
}
public BigDecimal(long val){
    this.intCompact = val;
    this.intval = (val == INFLATED)?INFLATED_BIGINT:null;
    this.scale = 0;
}
BigDecimal(double) 

而对于BigDecimal(double),当我们使用new BigDecimal(O.1)创建一个BigDecimal的时候,其实创建出来的值并不是整好等于0.1的,而是
0.1000000000000000055511151231257827021181583404541015625。这是因为double自身表示的只是一个近似值。

那么,无论我们使用new BigDecimall(O.1)还是new BigDecimal(O.1O)定义,他的近似值都是
0.1000000000000000055511151231257827021181583404541015625这个,那么他的标度就是这个数字的位数,即55。

其他的浮点数也同样的道理。对于new BigDecimal(1.0)这样的形式来说,因为他本质上也是个整数,所以他创建出来的数字的标度就是0。


所以,因为BigDecimal((1.O)和BigDecimal((1.00)的标度是一样的,所以在使用equals方法比较的时候,得到的结果就是true。

BigDecimal(String)


而对于BigDecimal(String),当我们使用new BigDecimal("O.1”)创建一个BigDecimal的时候,其实创建出来的值正好就是等于0.1的。那么他的标度也就是1。


如果使用new BigDecimal('0.10000”),那么创建出来的数就是0.10000,标度也就是5。
所以,因为BigDecimal(”1.0”)和BigDecimal(”1.00”)的标度不一样,所以在使用equals方法比较的时候,得到的结果就是false。

如何比较BigDecimal


前面,我们解释了BigDecimal的equals方法,其实不只是会比较数字的值,还会对其标度进行比较。所以,当我们使用equals方法判断判断两个数是否相等的时候,是极其严格的。
那么,如果我们只想判断两个BigDecimali的值是否相等,那么该如何判断呢?

BigDecimal中提供了compareTo方法,这个方法就可以只比较两个数字的值,如果两个数相等,则返回0.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值