BigDecimal是java.math包中提供的一种可以用来进行精确运算的类型。在进行金额表示 、金额计算等场景,不能使用double和float等类型,而是使用BigDecimal。

  BigDecimal表示数字和进行数字运算之外,代码中还会对BigDecimal进行相等判断。

最新阿里Java开发手册中指出

  禁止使用构造方法BigDecimal(double)的方式把double值转化为BigDecimal对象。
说明:
  BigDecimal(double)存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常。
如:
BigDecimal b = new BigDecimal(0.1F);实际的存值为:0.10000000149
正例:
  优先推荐入参为String的构造方法,或使用BigDecimal的valueOf方法,此方法内部其实执行了Double的toString,而Double的toString按double的实际表达的精度对尾数进行了截断。

BigDecimal b1 = new BigDecimal(“0.2”);
BigDecimal b2 = BigDecimal.valueOf(0.2);

下面进行出现这样原因的分析

  在经验不足时,我们会见到这样的低级错误

//判断两个数相等
if(bigDecimal1 == bigDecimal2){//.......
}

  因为BigDecimal 是对象,所以不能用==来判断这两个数字的值是否相等。

equals作判断的问题

//判断两个数相等
if(bigDecimal1.equals(bigDecimal2)){//......
}

以上的结果会和我们预想的结果有时候不一样。

BigDecimal  bigDecimal = new BigDecimal(1);
BigDecimal  bigDecimal2 = new BigDecimal(1);
System.out.println(bigDecimal1.equals(bigDecimal2));BigDecimal  bigDecimal3 = new BigDecimal(2);
BigDecimal  bigDecimal4 = new BigDecimal(2.0);
System.out.println(bigDecimal3.equals(bigDecimal4));BigDecimal  bigDecimal5 = new BigDecimal("2");
BigDecimal  bigDecimal6 = new BigDecimal("2.0");
System.out.println(bigDecimal5.equals(bigDecimal6));

以上代码输出结果为:

truetruefalse

BigDecimal的equals原理

  通过上面实验,使用BigDecimal的equals方法比较2和2.0时候,有时候是true(当使用int、double定义BigDecimal时),有时候是false(当使用String定义BigDecimal时)。

BigDecimal源码:

/*** 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).** @param  x {@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*/@Overridepublic 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());}

  在BigDecimal中的equals方法被重写,equals方法和compareTo并不一样,equals方法会比较两部分内容,分别是值(value)和标度(scale)。
  上面定义出来的两个BigDecimal对象,BigDecimal5和BigDecimal6的标度是不一样的。所以equals比较的结果为false。

标度不同原因

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

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

上面四个方法,创建出来的BigDecimal的标度是不同的。

BigDecimal(int)和BigDecimal(long)
BigDecimal(int)和BigDecimal(long),因为是整数,所以标度就是0

BigDecimal(double)
  对于BigDecimal(double),当我们使用new BigDecimal(0.1)创建一个BigDecimal的时候,其实创建出来的值并不是0.1,而是0.10000000000000000555111…的数。因为double自身表示的只是一个近似值。

  那么不论我们使用new BigDecimal(0.1)还是new BigDecimal(0.10)定义,他的近似值都不变。

  BigDecimal(1.0)和BigDecimal(1.00)的标度是一样的;

BigDecimal(String)
  对于BigDecimal(double),当我们使用new BigDecimal(“0.1”)创建一个BigDecimal的时候,创建出来的值就等于0.1.那么他的标度也是1.

  如果new BigDecimal(“0.10000”),那么创建出来的数就是0.10000,标度也就是5.

  所以BigDecimal(“3.0”)和BigDecimal(“3.00”)的标度不一样,所以使用equal方法比较的时候,得到的结果是false。

BigDecimal做比较

  当我们判断BigDecimal是否相等,用compareTo方法,如果两个数相等,则返回0.

BigDecimal  bigDecimal5 = new BigDecimal("2");
BigDecimal  bigDecimal6 = new BigDecimal("2.0000000");
System.out.println(bigDecimal5.compareTo(bigDecimal6));

输出结果:

0

注意:

compareTo源码

/*** Compares this {@code BigDecimal} with the specified* {@code BigDecimal}.  Two {@code BigDecimal} objects that are* equal in value but have a different scale (like 2.0 and 2.00)* are considered equal by this method.  This method is provided* in preference to individual methods for each of the six boolean* comparison operators ({@literal <}, ==,* {@literal >}, {@literal >=}, !=, {@literal <=}).  The* suggested idiom for performing these comparisons is:* {@code (x.compareTo(y)} &lt;<i>op</i>&gt; {@code 0)}, where* &lt;<i>op</i>&gt; is one of the six comparison operators.** @param  val {@code BigDecimal} to which this {@code BigDecimal} is*         to be compared.* @return -1, 0, or 1 as this {@code BigDecimal} is numerically*          less than, equal to, or greater than {@code val}.*/public int compareTo(BigDecimal val) {// Quick path for equal scale and non-inflated case.if (scale == val.scale) {long xs = intCompact;long ys = val.intCompact;if (xs != INFLATED && ys != INFLATED)return xs != ys ? ((xs > ys) ? 1 : -1) : 0;}int xsign = this.signum();int ysign = val.signum();if (xsign != ysign)return (xsign > ysign) ? 1 : -1;if (xsign == 0)return 0;int cmp = compareMagnitude(val);return (xsign > 0) ? cmp : -cmp;}

共同探讨学习技术创建技术氛围Day9884125

BigDecimal的equals方法做等值比较问题相关推荐

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

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

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

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

  3. bigdecimal js 判断等于0_为啥阿里禁用BigDecimal的equals方法做等值比较

    BigDecimal,相信对于很多人来说都不陌生,很多人都知道它的用法,这是一种java.math包中提供的一种可以用来进行精确运算的类型. 很多人都知道,在进行金额表示.金额计算等场景,不能使用do ...

  4. BigDecimal的equals方法

    BigDecimal作为浮点数据的一个处理对象,在平时用的挺多,但是今天才注意到它的equals方法有特殊的地方. equals方法是需要比较数值的精度的. BigDecimal b_1 = new ...

  5. scale和java比较_浅谈java中BigDecimal的equals与compareTo的区别

    这两天在处理支付金额校验的时候出现了点问题,有个金额比较我用了BigDecimal的equals方法来比较两个金额是否相等,结果导致金额比较出现错误(比如3.0与3.00的比较等). [注:以下所讲都 ...

  6. java面试题之hashCode与equals()方法

    @Data @Entity @Table(name = "tb_user") public class User {@Id@GeneratedValue(strategy = Ge ...

  7. JAVA-初步认识-第十一章-object类-equals方法覆盖

    一. 现在要谈论equals方法另一个方面.如果不写equals方法,直接用==来比较也是可以的,貌似equals方法有点多余. 现在不比较对象是否相等,而是比较对象中的特定内容,比如说对象的年龄,之 ...

  8. JAVA中重写equals()方法的同时要重写hashcode()方法

    object对象中的 public boolean equals(Object obj),对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true:注意:当此方法 ...

  9. 【Java常识】6.0面向对象认知和Eclipse的实用使用、==号和equals方法的区别

    1.曾经写过很多自以为很通俗易懂的面向对象的解释. 如下是目前最通俗的一种解释: 2.Eclipse的补充解释. 运行的快捷键:F11. 3.Eclipse快捷键大全 大全放本文最后,这里主要放常用的 ...

  10. 重写equals方法的hashcode_Java equals 和 hashCode 的这几个问题可以说明白吗?

    前言 上一篇文章 如何妙用Spring 数据绑定机制,灵魂追问 环节留下了一个有关 equals 和 hashcode 问题 .基础面试经常会碰到与之相关的问题,这不是一个复杂的问题,但很多朋友都苦于 ...

最新文章

  1. matlab 12脉波变压器,12脉波中频炉专用变压器外形尺寸
  2. ubuntu开机出现:system program problem detected
  3. 16 开机自动登录脚本_创建计划任务自动运行程序---运维无人值守
  4. 已被管理员、加密政策或凭据存储停用
  5. set python_python基础:集合-set()
  6. https连接java_如何从Java应用程序设置Https连接
  7. PostgreSQL csvlog 源码分析
  8. boost::geometry::detail::overlay::approximately_equals用法的测试程序)
  9. micropython按键控制流水灯_【micro:bit Micropython】The LED Display(1)控制像素点
  10. Java中实现定时任务的3种方法!
  11. Ubuntu环境搭建三:VIM配置
  12. [Vue warn]: Unknown custom element: <Top> - did you register the component correctly?
  13. 中国开放教育资源协会
  14. 1.1.27 word表格里的文字不显示
  15. 51单片机外围模块——DS1302时钟模块
  16. 风险分析(Barra风险模型)
  17. 高校先行,科技部公示10个国家级区块链重点项目 | 产业区块链发展周报
  18. 计算机 90学时培训总结,90学时培训心得体会
  19. 计算机管理无用怎么办,win7系统如何将资源管理器窗口中无用的图标删除掉?...
  20. vue实现实例搜索和排序

热门文章

  1. 【数据库】关系型数据库中实体间的关系
  2. JAVA 实现《JAVA打砖块》游戏
  3. 3d红苹果html,青苹果红苹果食疗功效大不同
  4. 【19调剂】湖南师范大学2019年信息科学与工程学院硕士研究生复试(含调剂)方案...
  5. 面试25个经典问题回答技巧
  6. IllegalArgumentException: Mapped Statements collection already contains value
  7. Tensorflow入门笔记——tf.app.flags.FLAGS用法介绍
  8. RESTful Web 服务:教程
  9. 如何获取免费的数字货币历史数据
  10. 【Linux】安装网易云全攻略