【BUG解决】关于BigDecimal与0的比较问题

这是一个很细小的知识点,但是很容易被忽略掉,导致系统问题,因此记录下来

问题背景

明明逻辑上看a和b都不为0才会调用除法,但是系统会报错:java.lang.ArithmeticException异常:

if (!a.equals(BigDecimal.ZERO) && !b.equals(BigDecimal.ZERO)) {BigDecimal divide = a.divide(b, 2, RoundingMode.HALF_UP);
}

异常截图:
在这里插入图片描述

分析

说明 a.equals(BigDecimal.ZERO)b.equals(BigDecimal.ZERO)同时为false,但是能引起java.lang.ArithmeticException异常的,b为0,所以 b.equals(BigDecimal.ZERO)的判断有误

然后就考虑到如果b的精度不是0,而是0.00,那么 b.equals(BigDecimal.ZERO)是不是会为false?

在 Java 中,BigDecimal 的 equals 方法比较的是值及其精度。

这是因为 BigDecimal.ZERO 表示的数字是 0, 精度(scale)为 0(即没有小数部分)。而 0.00 的精度则为 2,所以它们被认为是不同的对象。以下是示例代码:

BigDecimal b = new BigDecimal("0.00");
System.out.println(b.equals(BigDecimal.ZERO)); // 输出: false

如果想检查一个 BigDecimal 是否为零而不关心精度,使用 compareTo 方法,如下所示:

if (b.compareTo(BigDecimal.ZERO) == 0) {System.out.println("b 是零");
} else {System.out.println("b 不是零");
}

使用 compareTo 方法可以比较值而不考虑精度,这样,对于 0.00 和 0 的比较都是等于零的。

源码分析

这里我们对equals和compareTo的源码进行分析

(1) BigDecimal.equals() 的实现会比较数值和精度(scale):

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 compactValFor(this.intVal) == xs;return this.inflated().equals(xDec.inflated());
}

关键点:
首先比较精度(scale),如果不相同直接返回false
然后比较数值本身
所以 new BigDecimal("0.00").equals(BigDecimal.ZERO) 会返回false,因为精度不同(2 vs 0)

(2) compareTo 方法源码分析
BigDecimal.compareTo() 的实现:

public int compareTo(BigDecimal val) {// Quick path for equal scale and non-inflated caseif (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;
}

首先会比较符号(signum)
然后使用 compareMagnitude 比较绝对值
不直接比较精度(scale),而是会统一调整后再比较
new BigDecimal("0.00").compareTo(BigDecimal.ZERO) 会返回0,因为数值相同

最佳实践
当需要严格比较两个BigDecimal是否完全相同时(包括精度),使用 equals()
当只需要比较数值大小时,使用 compareTo()
检查是否为0时,推荐使用 compareTo()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/908150.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

千年之后再出发,铜官窑驶入微短剧的数字航道

过去一年里,微短剧已经成为走向全民关注、平台扶持、政策引导的“内容新主流”。从市值百亿的爆款平台到走出国门的“短剧出海”,微短剧正在重塑中国数字文化的表达方式与产业结构,也成为各地竞相争夺的“新蓝海”。 就在这样的背景下&#…

数据库管理-第333期 Oracle 23ai:RAC打补丁完全不用停机(20250604)

数据库管理333期 2025-06-04 数据库管理-第333期 Oracle 23ai:RAC打补丁完全不用停机(20250604)1 概念2 要求3 操作流程4 转移失败处理总结 数据库管理-第333期 Oracle 23ai:RAC打补丁完全不用停机(20250604&#xff0…

Trae CN IDE自动生成注释功能测试与效率提升全解析

Trae CN IDE 的自动注释功能可以通过 AI 驱动的代码分析生成自然语言注释,以下是具体测试方法和优势总结: 一、Python 代码注释生成测试 1. 测试环境 IDE:Trae CN IDE(需确认支持 Python)代码示例: def …

软考 系统架构设计师系列知识点之杂项集萃(79)

接前一篇文章:软考 系统架构设计师系列知识点之杂项集萃(78) 第141题 软件测试一般分为两个大类:动态测试和静态测试。前者通过运行程序发现错误,包括()等方法;后者采用人工和计算机…

有公网ip但外网访问不到怎么办?内网IP端口映射公网连接常见问题和原因

有公网IP但外网访问不到的核心原因通常包括:端口未正确映射、防火墙限制、DNS解析问题、运营商端口屏蔽或路由配置错误‌。需依次排查这些关键环节,其中端口映射和防火墙设置是最常见的原因。‌‌ ‌内网IP端口映射公网连接常见问题和原因及解决方案 1…

HttpServletResponse 对象用来做什么?

HttpServletResponse 对象是由 Servlet 容器创建并传递给 Servlet 的 service() 方法(以及间接传递给 doGet(), doPost() 等方法)的。它的核心作用是让 Servlet 能够向客户端(通常是浏览器)发送 HTTP 响应。 通过 HttpServletRes…

FTPS、HTTPS、SMTPS以及WebSockets over TLS的概念及其应用场景

一、什么是FTPS? FTPS,英文全称File Transfer Protocol with support for Transport Layer Security (SSL/TLS),安全文件传输协议,是一种对常用的文件传输协议(FTP)添加传输层安全(TLS)和安全套接层(SSL)加密协议支持的扩展协议。…

前端​​HTML contenteditable 属性使用指南

​​什么是 contenteditable? HTML5 提供的全局属性,使元素内容可编辑类似于简易富文本编辑器兼容性​​ 支持所有现代浏览器(Chrome、Firefox、Safari、Edge) 移动端(iOS/Android)部分键盘行为需测试 &l…

持续领跑中国异地组网路由器市场,贝锐蒲公英再次登顶销量榜首

作为国产远程连接SaaS服务的创领者,贝锐持续引领行业发展,旗下贝锐蒲公英异地组网路由器,凭借出色的技术实力和市场表现,斩获2024年线上电商平台市场销量份额中国第一的佳绩,充分彰显了其在网络解决方案与异地组网领域…

五大主流大模型推理引擎深度解析:llama.cpp、vLLM、SGLang、DeepSpeed和Unsloth的终极选择指南

在人工智能的竞技场上,大模型推理框架就像是为超级跑车精心调校的引擎系统——选对了能让你的AI应用一骑绝尘,选错了可能连"停车场"都开不出去。这些框架的核心价值在于将训练好的"大脑"转化为实际可用的"肌肉记忆",而选择标准则需要像职业赛…

前端面试二之运算符与表达式

目录 1.JavaScript 中的 和 运算符 2.|| (逻辑或) 运算符 与 ES6 默认参数的区别 与 ?? (空值合并运算符) 的区别 3.?.(可选链)运算符 (1). 安全访问深层嵌套属性 (2). 安全调用可能不存在的函数 (3). 安全访问数组元素 4.展开运算符 (..…

GB/T 24507-2020 浸渍纸层压实木复合地板检测

浸渍纸层压实木地板是指以一层或多层专用纸浸渍热固性氨基树脂,经干燥后铺装在胶合板基材正面,专用纸表面加耐磨层,基材背面可加平衡层,经热压、成型的地板。 GB/T 24507-2020 浸渍纸层压实木复合地板测试项目: 测试项…

AWS DocumentDB vs MongoDB:数据库的技术抉择

随着非关系型数据库在现代应用中的广泛应用,文档型数据库因其灵活的结构与出色的扩展性,逐渐成为企业开发与架构设计中的核心选择。在众多文档数据库中,MongoDB 凭借其成熟生态与社区支持占据主导地位;与此同时,AWS 提…

微信小程序实现运动能耗计算

微信小程序实现运动能耗计算 近我做了一个挺有意思的微信小程序,能够实现运动能耗的计算。只需要输入性别、年龄、体重、运动时长和运动类型这些信息,就能算出对应的消耗热量。 具体来说,在小程序里,性别不同,身体基…

三轴地磁传感器的主要应用场景

随着材料科学、微电子技术以及传感器技术的不断进步,三轴地磁传感器的性能将不断提升,包括提高精度、降低功耗、增强抗干扰能力等。 RAMSUN提供的是一款三轴地磁传感器采用第三代AMR技术,带有自动温度补偿的三轴磁传感器,该产品因…

使用 SseEmitter 实现 Spring Boot 后端的流式传输和前端的数据接收

1.普通文本消息的发送和接收 GetMapping("/stream")public SseEmitter streamResponse() {SseEmitter emitter new SseEmitter(0L); // 0L 表示永不超时Executors.newSingleThreadExecutor().execute(() -> {try {for (int i 1; i < 5; i) {emitter.send(&q…

nssm配置springboot项目环境,注册为windows服务

NSSM 的官方下载地址是&#xff1a;NSSM - the Non-Sucking Service Manager1 使用powershell输入命令,java项目需要手动配置和依赖nacos .\nssm.exe install cyMinio "D:\minio\启动命令.bat" .\nssm.exe install cyNacos "D:\IdeaProject\capacity\nacos-s…

WinCC学习系列-基础概念

从本节起&#xff0c;学习和了解西门子最新SCADA软件WinCC 8.0&#xff0c;将从基础概念开始&#xff0c;到入门操作&#xff08;创建项目、组态通信、组态过程画面、组态面板类型和变量结构、归档和显示值、组态消息&#xff09;&#xff0c;到高级应用&#xff08;WinCC选件、…

数据分析图表类型及其应用场景

说明&#xff1a;顶部HTML文件下载后可以直接查看&#xff0c;带有示图。 摘要 数据可视化作为现代数据分析的核心环节&#xff0c;旨在将复杂、抽象的数据转化为直观、易懂的图形形式。这种转化显著提升了业务决策能力&#xff0c;优化了销售与营销活动&#xff0c;开辟了新…

《江西棒垒球》败方mvp叫什么·棒球1号位

败方mvp也是MVP&#xff0c;以棒球运动为例&#xff0c;MLB&#xff08;美国职棒大联盟&#xff09;的个人奖项旨在表彰球员在不同领域的卓越表现&#xff0c;涵盖常规赛和季后赛的杰出成就。 常规赛核心奖项 最有价值球员奖&#xff08;MVP&#xff09; 定义&#xff1a;表彰…