浅谈java中BigDecimal的equals与compareTo的区别
作者:jingxian 发布时间:2023-09-02 07:20:22
这两天在处理支付金额校验的时候出现了点问题,有个金额比较我用了BigDecimal的equals方法来比较两个金额是否相等,结果导致金额比较出现错误(比如3.0与3.00的比较等)。
【注:以下所讲都是以sun jdk 1.4.2版本为例,其他版本实现未必一致,请忽略】
首先看一下BigDecimal的equals方法:
public boolean equals(Object x){
if (!(x instanceof BigDecimal))
return false;
BigDecimal xDec = (BigDecimal) x;
return scale == xDec.scale && intVal.equals(xDec.intVal);
}
可以看到BigDecimal的euquals方法是先判断要比较的数据类型,如果对象类型一致前提下同时判断精确度(scale)和值(BigInteger的equals方法)是否一致。
其实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).”只是自己没有去注意罢了!
再看一下compareTo方法:
public int compareTo(BigDecimal val){
/* Optimization: would run fine without the next three lines */
int sigDiff = signum() - val.signum();
if (sigDiff != 0)
return (sigDiff > 0 ? 1 : -1);
/* If signs match, scale and compare intVals */
BigDecimal arg[] = new BigDecimal[2];
arg[0] = this;arg[1] = val;
matchScale(arg);
return arg[0].intVal.compareTo(arg[1].intVal);
}
可以看到这个方法里面有个matchScale的处理,意思是把精确度低的那个对象转换为高精确度,然后再进行比较(同样是BigInteger的compareTo方法),matchScale的实现如下:
private static void matchScale(BigDecimal[] val) {
if (val[0].scale < val[1].scale)
val[0] = val[0].setScale(val[1].scale);
else if (val[1].scale < val[0].scale)
val[1] = val[1].setScale(val[0].scale);
}
做个简单测试:
System.out.println(new BigDecimal("1.2").equals(new BigDecimal("1.20"))); //输出false
System.out.println(new BigDecimal("1.2").compareTo(new BigDecimal("1.20")) == 0); //输出true
另外注意到我上面BigDecimal的构造方法里面传入的都是字符串,如果传入的是数字类型的话会有什么结果,大家可以自己测试一下,然后分析一下原因:
System.out.println(new BigDecimal("1.2").equals(new BigDecimal("1.20"))); //输出false
System.out.println(new BigDecimal("1.2").compareTo(new BigDecimal("1.20")) == 0); //输出true
System.out.println(new BigDecimal(1.2).equals(new BigDecimal("1.20"))); //输出是?
System.out.println(new BigDecimal(1.2).compareTo(new BigDecimal("1.20")) == 0); //输出是?
System.out.println(new BigDecimal(1.2).equals(new BigDecimal(1.20))); //输出是?
System.out.println(new BigDecimal(1.2).compareTo(new BigDecimal(1.20)) == 0);//输出是?
最后结论是:对于BigDecimal的大小比较,用equals方法的话会不仅会比较值的大小,还会比较两个对象的精确度,而compareTo方法则不会比较精确度,只比较数值的大小。
最后鄙视一下自己,用了这么多年的Java语言,连基本的常识都没搞清楚!


猜你喜欢
- 一、概述我们对于这个图片肯定会非常熟悉,这两幅图片我们都可以看做是一个文件结构,对于这样的结构我们称之为树形结构。在数据结构中我们了解到可以
- 本章目标整合 Mybatis ,并集成 Druid 数据源可视化监控 Druid 数据源使用 JPA 生成数据表利用注解实现数据库的事物利用
- 常量是在编译时已知并在程序的生存期内不发生更改的不可变值。常量使用 const 修饰符进行声明。只有 C# 内置类型(System.Obje
- 本文实例为大家分享了C#实现会移动的文字效果的具体代码,供大家参考,具体内容如下1 题目描述(1)Form1窗体设计界面如下:(2)窗体左侧
- 1、概括在博客中,我们将讨论如何让Spring Security OAuth2实现使用JSON Web Tokens。2、Maven 配置首
- 1. 为什么使用线程池诸如 Web 服务器、数据库服务器、文件服务器或邮件服务器之类的许多服务器应用程序都面向处理来自某些远程来源的大量短小
- 谷歌的AI击败了一位围棋大师,是一种衡量人工智能突然的快速发展的方式,也揭示了这些技术如何发展而来和将来可以如何发展。人工智能是一种未来性的
- Condition是在Spring 4.0 增加的条件判断功能,通过这个可以功能可以实现选择性的创建 Bean操作。思考:SpringBoo
- 1.什么是PDF/UA文件PDF/UA,即Universally Accessible PDF,该格式的PDF文件是于2012年8月以ISO
- 一、介绍1、"Lambda表达式"是一个特殊的匿名函数,简化了匿名委托的使用,是一种高效的类似于函数式编程的表达式,La
- 本文实例为大家分享了Android实现滑动开关效果的具体代码,供大家参考,具体内容如下自定义开关控件Android自定义控件一般有三种方式
- 因为支持csv,所以就一块写上了Workbook,Worksheet using Aspose.Cells(第三方)把Excel读取到属性对
- 延伸:以后除了可以为实体类注入属性,还可以为配置类注入相关的配置信息1.编写实体类@Component@ConfigurationPrope
- JAVA堆内存管理是影响性能主要因素之一。堆内存溢出是JAVA项目非常常见的故障,在解决该问题之前,必须先了解下JAVA堆内存是怎么工作的。
- 本文实例讲述了Android设置PreferenceCategory背景颜色的方法。分享给大家供大家参考。具体分析如下:大家可能遇到,Pre
- Windows服务在Visual Studio 以前的版本中叫NT服务,在VS.net启用了新的名称。用Visual C# 创建Window
- 一、概念String代表字符串,java语言中所有双引号的字符串都是String的对象,不管是否是new出来的对象。二、特点1.String
- 设置变量nRowNum = 8; % 画布行数nColNum = 9; % 画布列数offset_x = 0;% 红车坐标起点offset_
- Dubbo过滤器概述Dubbo中的过滤器和Web应用中的过滤器的概念是一样的,提供了在服务调用前后插入自定义逻辑的途径。过滤器是整个Dubb
- Spring的最基本的能力就是DI,即依赖注入,或控制反转,它可以为Bean注入其依赖的其他Bean。一个Bean依赖其他Bean一般是通过