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

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

所以,很多支付、电商、金融等业务中,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
truefalse

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方法。

地址:https://www.toutiao.com/i6874812439561503243/
作者:java互联网架构

bigdecimal js 判断等于0_为啥阿里禁用BigDecimal的equals方法做等值比较相关推荐

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

    目录 前言 BigDecimal 做等值比较 使用 compareTo 方法 PS 前言 BigDecimal 是 java.math 包中提供的一种可以用来进行精确运算的类型.所以,在支付.电商等业 ...

  2. 为什么阿里巴巴禁止使用BigDecimal的equals方法做等值比较?

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! BigDecimal,相信对于很多人来说都不陌生,很多人都 ...

  3. js判断浏览器是否安装或启用了flash的方法总结

    目录 # js判断浏览器是否安装或启用了flash的方法 # chrome浏览器启用flash插件的方法 # 参考 # js判断浏览器是否安装或启用了flash的方法 在传统浏览器,可以使用windo ...

  4. 用session实现html登录页面跳转页面跳转页面跳转,js判断登录与否并确定跳转页面的方法...

    这篇文章主要介绍了js判断登录与否并确定跳转页面的方法,涉及Ajax及session使用的技巧,非常具有实用价值,需要的朋友可以参考下 本文实例讲述了js判断登录与否并确定跳转页面的方法.分享给大家供 ...

  5. html判断坐标,js判断鼠标位置是否在某个div中的方法

    本文实例讲述了js判断鼠标位置是否在某个div中的方法.分享给大家供大家参考,具体如下: div的onmouseout事件让div消失时,会出现这样的情况,就是当鼠标移至div中的其它内容时,此时也判 ...

  6. html 登录判断跳转页面跳转页面,js判断登录与否并确定跳转页面的方法

    本文实例讲述了js判断登录与否并确定跳转页面的方法.分享给大家供大家参考.具体如下: 使用session存储,确定用户是否登录,从而确定页面跳转至哪个页面. 判断本地有无customerID: fun ...

  7. js判断移动端是否安装某款app的方法

    以下js代码是判断移动端是否安装某款app的方法,分享给大家供大家参考,具体内容如下: if(navigator.userAgent.match(/(iPhone|iPod|iPad);?/i)) { ...

  8. html js验证登录页面,js判断登录与否并确定跳转页面的方法

    本文实例讲述了js判断登录与否并确定@R_384_404@面的方法.分享给大家供大家参考.具体如下: 使用session存储,确定用户是否登录,从而确定页面跳转至哪个页面. 判断本地有无custome ...

  9. iOS js判断移动端是否安装某款app的方法

    一.判断是那种设备 var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端 二. ios设备:原理:判断是否认识这个协议,认识则 ...

最新文章

  1. VM虚拟机中的centos6.3命令行模式添加GCC
  2. oracle性能调优学习0622
  3. 探索区块链-挖框体验
  4. ESP8266和MQTT
  5. WinForm界面开发之布局控件WeifenLuo.WinFormsUI.Docking的使用
  6. VS调试时怎么跳过for循环?
  7. 方舟服务器维护公告11月19日,明日方舟11月19日10点停机维护 更新内容一览
  8. linux第一季运维001
  9. PB 级大规模 Elasticsearch 集群运维与调优实践
  10. sql server 2005技术大全_3年2.16~3.2万吨!上机数控子公司与新疆大全签订多晶硅采购长单...
  11. Windows8 10设置程序为 系统默认浏览器
  12. Android Touch 事件的分发和消费机制
  13. jquery html app,jquery .html()vs .append()
  14. cfe刷机教程 斐讯k3_斐讯K3刷机教程官改V2.1D或者其它版本教程
  15. 班门弄斧之机械设计理论
  16. 原生JS调取PC端摄像头源码记录
  17. 想要成为一名合格的数据分析师,需要学习哪些类型的书
  18. 亚马逊出单技巧 掌握财富密码
  19. 直面大数据撞击这个时代——畅享网成功举办大数据应用沙龙
  20. iOS基础 获取状态栏的高度

热门文章

  1. aptitude 命令_C-命令行参数Aptitude问题与解答
  2. jqgrid本地数据例子_办公系统私有云公有云和本地化部署,你选哪个?
  3. 我们在使用计算机时,不能做什么?,11秋季学期计算机应用技术基础学习周期_01任务-在线作业[1]1...
  4. 定期定量采购_企业常见的六种采购策略
  5. php猴子找大王算法,教程方法;php实现猴子选大王问题算法实例电脑技巧-琪琪词资源网...
  6. Python | 使用__del __()和__init __()实现析构函数和构造函数的示例
  7. linux 文件浏览器_浏览Linux文件系统
  8. __asm___错误:“”前应有'=',',',',','asm'或'_attribute_'
  9. 设置devenv命令的启动版本
  10. Ray.tune可视化调整超参数Tensorflow 2.0