文章图片
前言
BigDecimal 是 java.math 包中提供的一种可以用来进行精确运算的类型。所以,在支付、电商等业务中,BigDecimal 的使用非常频繁。而且其内部自带了很多方法,如加,减,乘,除等运算方法都是可以直接调用的。除了需要用 BigDecimal 表示数字和进行数字运算以外,代码中还经常需要对于数字进行相等判断。
文章图片
那么为什么会有这样的要求呢~ 其中的奥秘是什么呢~ 请各位小伙伴听我娓娓道来...
BigDecimal 做等值比较
public static void main(String[] args) {
BigDecimal bigDecimal1 = new BigDecimal(1);
BigDecimal bigDecimal2 = new BigDecimal(1);
if(bigDecimal1 == bigDecimal2){
//等值比较
}
}
相信聪明的小伙伴一眼就可以看出来上面的代码是有问题的,因为 BigDecimal 是对象,不能使用 == 来做等值判断。
如果我们使用 BigDecimal 的 equals 方法做等值比较是不是可以呢?
public static void main(String[] args) {
BigDecimal bigDecimal1 = new BigDecimal(1);
BigDecimal bigDecimal2 = new BigDecimal(1);
if(bigDecimal1.equals(bigDecimal2)){
//等值比较
}
}
这里我先卖个关子,咱们跑跑代码来看看能不能用 BigDecimal 的 equals 方法做等值比较(●'?'●),
public static void main(String[] args) {
BigDecimal bigDecimal1 = new BigDecimal(1);
BigDecimal bigDecimal2 = new BigDecimal(1);
System.out.println(bigDecimal1.equals(bigDecimal2));
BigDecimal bigDecimal3 = new BigDecimal(1);
BigDecimal bigDecimal4 = new BigDecimal(1.0);
System.out.println(bigDecimal3.equals(bigDecimal4));
BigDecimal bigDecimal5 = new BigDecimal("1");
BigDecimal bigDecimal6 = new BigDecimal("1.0");
System.out.println(bigDecimal5.equals(bigDecimal6));
}
文章图片
我们可以发现,在使用 BigDecimal 的 equals 方法对 1 和 1.0 进行比较的时候:使用 int、double 定义 BigDecimal 结果是 true;使用 String 定义 BigDecimal 结果是false,为什么会出现这种情况呢?
我们一起来看看 equals 方法的源码
/**
* Compares this {@code BigDecimal} with the specified
* {@code Object} for equality.Unlike {@link
* #compareTo(BigDecimal) compareTo}, this method considers two
* {@code 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).
*
* @paramx {@code Object} to which this {@code BigDecimal} is
*to be compared.
* @return {@code true} if and only if the specified {@code Object} is a
*{@code BigDecimal} whose value and scale are equal to this
*{@code BigDecimal}'s.
* @see#compareTo(java.math.BigDecimal)
* @see#hashCode
*/
@Override
public boolean equals(Object x) {
if (!(x instanceof BigDecimal))
return false;
BigDecimal xDec = (BigDecimal) x;
if (x == this)
return true;
if (scale != xDec.scale)
return false;
long s = this.intCompact;
long xs = xDec.intCompact;
if (s != INFLATED) {
if (xs == INFLATED)
xs = compactValFor(xDec.intVal);
return xs == s;
} else if (xs != INFLATED)
return xs == compactValFor(this.intVal);
return this.inflated().equals(xDec.inflated());
}
其实咱们从方法的注释中就能找到答案:equals 方法会比较两部分内容,分别是值(value)和标度(scale),也就是说 bigDecimal5 和 bigDecimal6 的值虽然相同,但是标度是不一样的。
咱们打个断点,debug 一下看看~
文章图片
我们可以看见 bigDecimal5 的标度值是0,而bigDecimal6的标度值是1,所以 bigDecimal5 和 bigDecimal6 的比较结果是false (●ˇ?ˇ●)
那么这时候又产生了一个疑问:为什么标度不同呢?
嘻嘻~ 各位小伙伴稍安勿躁,请听我娓娓道来~
BigDecimal 一共有以下 4 个构造方法:
- BigDecimal(int)
- BigDecimal(double)
- BigDecimal(long)
- BigDecimal(String)
/**
* Translates an {@code int} into a {@code BigDecimal}.The
* scale of the {@code BigDecimal} is zero.
*
* @param val {@code int} value to be converted to
*{@code BigDecimal}.
* @since1.5
*/
public BigDecimal(int val) {
this.intCompact = val;
this.scale = 0;
this.intVal = null;
}``````
/**
* Translates a {@code long} into a {@code BigDecimal}.The
* scale of the {@code BigDecimal} is zero.
*
* @param val {@code long} value to be converted to {@code BigDecimal}.
* @since1.5
*/
public BigDecimal(long val) {
this.intCompact = val;
this.intVal = (val == INFLATED) ? INFLATED_BIGINT : null;
this.scale = 0;
}
而对于 BigDecimal (double) 来说,当我们使用 new BigDecimal (0.1) 创建一个对象的时候,其实创建出来的对象的值并不是等于0.1,而是等于0.1000000000000000055511151231257827021181583404541015625
文章图片
我们再打个断点,debug一下看看标度值是多少
文章图片
我们可以看到标度值是55,这个值是怎么来的呢?其实很简单,这个标度值就是这个数字的位数,其他的浮点数也同样的道理。对于 new BigDecimal (1.0),和new BigDecimal (1.00) 这样的形式来说,因为他本质上也是个整数,所以他创建出来的数字的标度就是0。
最后我们再看看 BigDecimal(String) ,当我们使用 new BigDecimal ("0.1") 创建一个 BigDecimal 的时候,其实创建出来的值正好就是等于 0.1 的。那么他的标度也就是 1;如果使用 new BigDecimal ("0.10000"),那么创建出来的数就是 0.10000,标度也就是 5。
讲到这里相信各位小伙伴也明白了为什么 bigDecimal5 和 bigDecimal6 用equals 方法做等值比较的结果是false了 O(∩\_∩)O
如果我们只想判断两个 BigDecimal 的值是否相等,那么该如何判断呢?
在 BigDecimal 中也为我们提供了一个方法 —— compareTo 方法,这个方法就可以只比较两个数字的值,如果两个数相等,则返回 0。
文章图片
我们把 equals 换成 compareTo 后可以发现,bigDecimal5 和 bigDecimal6 等值比较的结果是0,也就是说明这二者的值是相等的。
P.S. 所以我们在做等值比较的时候不要随便用 BigDecimal 的 equals 方法,如果只是要对数值作比较,就果断选择 compareTo 方法就搞定拉~
小结 本人经验有限,有些地方可能讲的没有特别到位,如果您在阅读的时候想到了什么问题,欢迎在评论区留言,我们后续再一一探讨?
如果本文对你有帮助的话,请不要吝啬你的赞,谢谢!
【为什么不能使用 BigDecimal 的 equals 方法做等值比较】
文章图片
推荐阅读
- JAVA|第十一届蓝桥杯校内赛/校内选拔赛(2020蓝桥杯校选3-java)部分解题思路
- java|五个经典的破坏双亲委派场景,Java被啪啪打脸
- 人工智能|温故知新-软件生存周期和过程模型
- java|温故知新-什么是软件工程
- 科普学习|微服务架构设计和拆分
- java|四种常用的微服务架构拆分方式
- 面试官(Java 设计原则中,为什么反复强调组合要优先于继承())
- 项目资料|基于JAVA+SpringBoot+Mybatis+Vue+MYSQL的智慧养老管理系统
- java项目精品实战案例|基于Java+SpringBoot+vue+node.js实现直行车租赁平台管理系统