关于java:为什么阿里巴巴禁止使用BigDecimal的equals方法做等值比较

2次阅读

共计 3693 个字符,预计需要花费 10 分钟才能阅读完成。

GitHub 17k Star 的 Java 工程师成神之路,不来理解一下吗!

GitHub 17k Star 的 Java 工程师成神之路,真的不来理解一下吗!

GitHub 17k Star 的 Java 工程师成神之路,真的真的不来理解一下吗!

BigDecimal,置信对于很多人来说都不生疏,很多人都晓得他的用法,这是一种 java.math 包中提供的一种能够用来进行准确运算的类型。

很多人都晓得,在进行金额示意、金额计算等场景,不能应用 double、float 等类型,而是要应用对精度反对的更好的 BigDecimal。

所以,很多领取、电商、金融等业务中,BigDecimal 的应用十分频繁。而且不得不说这是一个十分好用的类,其外部自带了很多办法,如加,减,乘,除等运算办法都是能够间接调用的。

除了须要用 BigDecimal 示意数字和进行数字运算以外,代码中还常常须要对于数字进行相等判断。

对于这个知识点,在最新版的《阿里巴巴 Java 开发手册》中也有阐明:

这背地的思考是什么呢?

我在之前的 CodeReview 中,看到过以下这样的低级谬误:

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

这种谬误,置信聪慧的读者一眼就能够看出问题,因为 BigDecimal 是对象,所以不能用 == 来判断两个数字的值是否相等。

以上这种问题,在有肯定的教训之后,还是能够防止的,然而聪慧的读者,看一下以下这行代码,你感觉他有问题吗:

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

能够明确的通知大家,以上这种写法,可能失去的后果和你料想的不一样!

先来做个试验,运行以下代码:

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 原理

通过以上代码示例,咱们发现,在应用 BigDecimal 的 equals 办法对 1 和 1.0 进行比拟的时候,有的时候是 true(当应用 int、double 定义 BigDecimal 时),有的时候是 false(当应用 String 定义 BigDecimal 时)。

那么,为什么会呈现这样的状况呢,咱们先来看下 BigDecimal 的 equals 办法。

在 BigDecimal 的 JavaDoc 中其实曾经解释了其中起因:

Compares this  BigDecimal with the specified Object for equality.  Unlike compareTo, this method considers two BigDecimal objects equal only if they are equal in value and scale (thus 2.0 is not equal to 2.00 when compared by  this method)

大略意思就是,equals 办法和 compareTo 并不一样,equals 办法会比拟两局部内容,别离是值(value)和精度(scale)

对应的代码如下:

所以,咱们以上代码定义进去的两个 BigDecimal 对象(bigDecimal4 和 bigDecimal5)的精度是不一样的,所以应用 equals 比拟的后果就是 false 了。

尝试着对代码进行 debug,在 debug 的过程中咱们也能够看到 bigDecimal4 的精度时 0,而 bigDecimal5 的精度是 1。

到这里,咱们大略解释分明了,之所以 equals 比拟 bigDecimal4 和 bigDecimal5 的后果是 false,是因为精度不同。

那么,为什么精度不同呢?为什么 bigDecimal2 和 bigDecimal3 的精度是一样的(当应用 int、double 定义 BigDecimal 时),而 bigDecimal4 和 bigDecimal5 却不一样(当应用 String 定义 BigDecimal 时)呢?

为什么精度不同

这个就波及到 BigDecimal 的精度问题了,这个问题其实是比较复杂的,因为不是本文的重点,这外面就简略介绍一下吧。大家感兴趣的话,前面独自讲。

首先,BigDecimal 一共有以下 4 个构造方法:

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

以上四个办法,创立进去的的 BigDecimal 的精度是不同的。

BigDecimal(long) 和 BigDecimal(int)

首先,最简略的就是BigDecimal(long) 和 BigDecimal(int),因为是整数,所以精度就是 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(0.1)创立一个 BigDecimal 的时候,其实创立进去的值并不是整好等于 0.1 的,而是 0.1000000000000000055511151231257827021181583404541015625。这是因为 doule 本身示意的只是一个近似值。

那么,无论咱们应用 new BigDecimal(0.1)还是 new BigDecimal(0.10)定义,他的近似值都是 0.1000000000000000055511151231257827021181583404541015625 这个,那么他的精度就是这个数字的位数,即 55。

其余的浮点数也同样的情理。对于 new BigDecimal(1.0)这样的模式来说,因为他实质上也是个整数,所以他创立进去的数字的精度就是 0。

所以,因为 BigDecimal(1.0)和 BigDecimal(1.00)的精度是一样的,所以在应用 equals 办法比拟的时候,失去的后果就是 true。

BigDecimal(string)

而对于 BigDecimal(double),当咱们应用 new BigDecimal(“0.1”)创立一个 BigDecimal 的时候,其实创立进去的值正好就是等于 0.1 的。那么他的精度也就是 1。

如果应用 new BigDecimal(“0.10000”),那么创立进去的数就是 0.10000,精度也就是 5。

所以,因为 BigDecimal(“1.0”)和 BigDecimal(“1.00”)的精度不一样,所以在应用 equals 办法比拟的时候,失去的后果就是 false。

如何比拟 BigDecimal

后面,咱们解释了 BigDecimal 的 equals 办法,其实不只是会比拟数字的值,还会对其精度进行比拟。

所以,当咱们应用 equals 办法判断判断两个数是否相等的时候,是极其严格的。

那么,如果咱们只想判断两个 BigDecimal 的值是否相等,那么该如何判断呢?

BigDecimal 中提供了 compareTo 办法,这个办法就能够只比拟两个数字的值,如果两个数相等,则返回 0。

    BigDecimal bigDecimal4 = new BigDecimal("1");
    BigDecimal bigDecimal5 = new BigDecimal("1.0000");
    System.out.println(bigDecimal4.compareTo(bigDecimal5));

以上代码,输入后果:

0

其源码如下:

总结

BigDecimal 是一个十分好用的示意高精度数字的类,其中提供了很多丰盛的办法。

然而,他的 equals 办法应用的时候须要审慎,因为他在比拟的时候,不仅比拟两个数字的值,还会比拟他们的精度,只有这两个因素有一个是不相等的,那么后果也是 false、

如果读者想要对两个 BigDecimal 的数值进行比拟的话,能够应用 compareTo 办法。

关注公众号:程序员面试现场。回复『手册』获取手册最新版。

正文完
 0