Java开发手册中为什么禁止使用BigDecimal的equals方法做等值比较以及为什么禁止使用double直接构造BigDecimal

场景

阿里Java开发手册嵩山版中明确指出:

1、BigDecimal的等值比较应使用compareTo()方法,而不是equals()方法

equals()方法会比较值和精度(1.0与1.00返回结果为false),而compareTo()则会忽略精度

2、禁止使用构造方法BigDecimal(double)的方式把double值转换为BigDecimal对象

BigDecimal(double)存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常

注:

博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主

Java开发手册为什么禁止使用BigDecimal的equals方法做等值比较?

BigDecimal,相信对于很多人来说都不陌生,很多人都知道他的用法,这是一种java.math 包中提供的一种可以用来

扫描二维码关注公众号,回复: 15482674 查看本文章

进行精确运算的类型。在进行金额表示、金额计算等场景,不能使用 double、float 等类型,而是要使用对精度支持

更好的 BigDecimal。其内部自带了很多方法,如加,减,乘,除等运算方法都是可以直接调用的。除了需要用

BigDecimal 表示数字和进行数字运算以外,代码中还经常需要对于数字进行相等判断。Java开发手册中有说明:

BigDecimal的等值比较应使用compareTo()方法,而不是equals()方法

equals()方法会比较值和精度(1.0与1.00返回结果为false),而compareTo()则会忽略精度。

看下面的示例:

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

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

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

通过以上代码示例,我们发现,在使用 BigDecimal 的 equals 方法对 1 和 1.0 进行比较的时候,

有的时候是 true(当使用 int、double 定义 BigDecimal 时),有的时候是false(当使用 String 定义 BigDecimal 时)。

查看源码可知,equals会比较标度scale,见源码

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

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

BigDecimal(double) 无论我们使用 new BigDecimal(0.1)还是 new BigDecimal(0.10)定义,他的近似值

都是0.1000000000000000055511151231257827021181583404541015625

这个,那么他的标度就是这个数字的位数,即 55

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

BigDecimal(String)  BigDecimal(“1”)和 BigDecimal(“1.0”)的标度不一样

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

BigDecimal bigDecimal6 = new BigDecimal("1");

BigDecimal bigDecimal7 = new BigDecimal("1.0000");

System.out.println(bigDecimal6.compareTo(bigDecimal7)); //0

Java开发手册为什么禁止使用double直接构造BigDecimal

Java开发手册中要求 禁止使用构造方法BigDecimal(double)的方式把double值转换为BigDecimal对象

说明:BigDecimal(double)存在精度损失风险,在精确计算或值比较的场景中可能会导致业务逻辑异常

比如下面,实际存储值为0.10000000149

BigDecimal bigDecimal = new BigDecimal(0.1F);

优先推荐入参为String 的构造方法,或使用BigDecimal的valueOf方法,此方法其实内部执行了Double的toString,

而Double的toString按double的实际能表达的精度对尾数进行了截断。

BigDecimal bigDecimal1 = new BigDecimal("0.1");

BigDecimal bigDecimal2 = BigDecimal.valueOf(0.1);

Java中doble为什么不精确?

十进制小数转成二进制,一般采用”乘 2 取整,顺序排列”方法,如 0.625 转成二进制的表示为 0.101。

但是,并不是所有小数都能转成二进制,如 0.1 就不能直接用二进制表示,他的二进制是 0.000110011001100...

这是一个无限循环小数。所以,计算机是没办法用二进制精确的表示 0.1 的。也就是说,在计算机中,

很多小数没办法精确的使用二进制表示出来。在 Java 中,使用 float 和 double 分别用来表示单精度浮点数和双精度浮点数。

所谓精度不同,可以简单的理解为保留有效位数不同。采用保留有效位数的方式近似的表示小数。

猜你喜欢

转载自blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/130991678