大家好,我是苏三,又跟大家见面了。

前言

在日常开发中,很多小伙伴喜欢用 BigDecimal 来处理精确计算,比如钱、分数、比例啥的。

理论上,它比 double 或 float 更精确,但如果你用得不对,精度丢失的问题会让你哭晕在厕所。

今天我们就来聊聊 ,错误使用BigDecimal的6种场景,为什么会发生问题,以及怎么避免问题,希望对你会有所帮助。

1 直接用浮点数初始化

不少小伙伴习惯这样写:

BigDecimal num = new BigDecimal(0.1);
System.out.println(num);

打印结果:0.1000000000000000055511151231257827021181583404541015625

并非打印的:0.1

问题出在哪?

这不是 BigDecimal 的问题,而是浮点数本身的“锅”。

在Java中,double的精度有限的,0.1 转换成二进制是个无限循环小数,直接传进去会带上误差。

正确姿势是传字符串:

BigDecimal num = new BigDecimal("0.1");
System.out.println(num);

打印结果:0.1,是正确的。

注意:永远不要用 BigDecimal(double) 构造函数,用字符串或整数更靠谱。也可以使用BigDecimal.valueOf()函数。

2 加减乘除时不设精度

有些小伙伴做加减乘除的时候,直接写:

BigDecimal a = new BigDecimal("1.03");
BigDecimal b = new BigDecimal("0.42");
//减法
BigDecimal result = a.subtract(b);
System.out.println(result);

打印结果::0.61,没问题。

但问题在 除法 时:

BigDecimal c = new BigDecimal("10");
BigDecimal d = new BigDecimal("3");
BigDecimal result = c.divide(d);

运行直接炸了:java.lang.ArithmeticException: Non-terminating decimal expansion

报错的根本原因:10/3 是无限小数,BigDecimal 默认不保留小数点后面,精度溢出。

那么,我们要如何优化呢?

答:加一个 MathContext 或指定精度。

例如:

BigDecimal result = c.divide(d, 2, RoundingMode.HALF_UP);
System.out.println(result);

打印结果:3.33,可以正常运行。

因此,我们需要注意,在BigDecimal 做除法时 ,必须指定精度。

3 用 equals 判断相等

BigDecimal 的 equals 会比较 值和精度,这坑了不少人:

BigDecimal x = new BigDecimal("1.0");
BigDecimal y = new BigDecimal("1.00"); System.out.println(x.equals(y));

打印结果:false。

尽管 1.0 和 1.00 的数值相等,但精度不一样,equals 判定为不同。

优化方法,用 compareTo 比较数值:

例如:

System.out.println(x.compareTo(y) == 0);

打印结果:true

需要特别注意的地方是:我们在判断两个BigDecimal对象是否相等时,应该用 compareTo方法,别用 equals方法。

4 使用 scale 时忽视实际含义

有些小伙伴搞不清 scale(小数位数)和 precision(总位数)的区别,直接写:

BigDecimal num = new BigDecimal("123.4500");
System.out.println(num.scale());

打印结果:4

但如果你写成下面这样的:

BigDecimal stripped = num.stripTrailingZeros();
System.out.println(stripped.scale());

打印结果却是:2

scale 会发生变化,搞不好会影响后续计算。

那么,我们要如何优化方法呢?

答:明确 scale 的含义。

如果要固定小数位,使用 setScale:

BigDecimal fixed = num.setScale(2, RoundingMode.HALF_UP);
System.out.println(fixed);

打印结果:123.45。

我们不要混淆 scale 和 precision,必要时显式设置小数位数。

5 忽略不可变性

BigDecimal 是不可变的,但有些小伙伴会这样写:

BigDecimal sum = new BigDecimal("0");
for (int i = 0; i < 5; i++) {
sum.add(new BigDecimal("1"));
}

打印结果:0

问题原因是 add 方法不会改变原对象,而是返回一个新的 BigDecimal 实例。

那么,我们要如何优化呢?

答:用变量接住返回值。

BigDecimal sum = new BigDecimal("0");
for (int i = 0; i < 5; i++) {
sum = sum.add(new BigDecimal("1"));
}
System.out.println(sum);

打印结果是:5

BigDecimal 操作后需要接住新实例。

6 忽视性能问题

BigDecimal 是很精确,但也很慢。

如果大量计算时用 BigDecimal,会拖累性能,比如计算利息:

BigDecimal principal = new BigDecimal("10000");
BigDecimal rate = new BigDecimal("0.05");
BigDecimal interest = principal.multiply(rate);

一个循环里搞上百万次,性能直接拉垮。

那么,这种情况我们又该如何优化呢?

答:能用整数就用整数(比如分代替元)。

批量计算时,用 double 计算,结果最后转换成 BigDecimal。

double principal = 10000;
double rate = 0.05;
BigDecimal interest = BigDecimal.valueOf(principal * rate);
System.out.println(interest);

打印结果:500.00

参与大批量计算时,两个BigDecimal对象直接计算会比较慢,尽量少用,能优化的地方别放过。

写在最后

BigDecimal 是个非常强大的数字类工具,但也是个“细节狂魔”。

只有用对了,你才能真正享受它带来的好处,否则就是自找麻烦。

希望这篇文章能帮到你,不要再踩坑。

如果有其他用法上的困惑,欢迎留言讨论,我们一起成长!

最后说一句(求关注,别白嫖我)

如果这篇文章对您有所帮助,或者有所启发的话,帮忙关注一下我的同名公众号:苏三说技术,您的支持是我坚持写作最大的动力。

求一键三连:点赞、转发、在看。

关注公众号:【苏三说技术】,在公众号中回复:进大厂,可以免费获取我最近整理的10万字的面试宝典,好多小伙伴靠这个宝典拿到了多家大厂的offer。

生产环境BigDecimal用错了,已哭晕在厕所。。。的更多相关文章

  1. (转) 将ASP.NET Core应用程序部署至生产环境中(CentOS7)

    原文链接: http://www.cnblogs.com/ants/p/5732337.html 阅读目录 环境说明 准备你的ASP.NET Core应用程序 安装CentOS7 安装.NET Cor ...

  2. 将ASP.NET Core应用程序部署至生产环境中(CentOS7)

    这段时间在使用Rabbit RPC重构公司的一套系统(微信相关),而最近相关检验(逻辑测试.压力测试)已经完成,接近部署至线上生产环境从而捣鼓了ASP.NET Core应用程序在CentOS上的部署方 ...

  3. 将ASP.NET Core应用程序部署至生产环境中(CentOS7)(转)

    阅读目录 环境说明 准备你的ASP.NET Core应用程序 安装CentOS7 安装.NET Core SDK for CentOS7. 部署ASP.NET Core应用程序 配置Nginx 配置守 ...

  4. 生产环境中CentOS7部署NET Core应用程序

    NET Core应用程序部署至生产环境中(CentOS7) 阅读目录 环境说明 准备你的ASP.NET Core应用程序 安装CentOS7 安装.NET Core SDK for CentOS7. ...

  5. 中小研发团队架构实践之生产环境诊断工具WinDbg 三分钟学会.NET微服务之Polly 使用.Net Core+IView+Vue集成上传图片功能 Fiddler原理~知多少? ABP框架(asp.net core 2.X+Vue)模板项目学习之路(一) C#程序中设置全局代理(Global Proxy) WCF 4.0 使用说明 如何在IIS上发布,并能正常访问

    中小研发团队架构实践之生产环境诊断工具WinDbg 生产环境偶尔会出现一些异常问题,WinDbg或GDB是解决此类问题的利器.调试工具WinDbg如同医生的听诊器,是系统生病时做问题诊断的逆向分析工具 ...

  6. CentOS7.1下生产环境Keepalived+Nginx配置

    CentOS7.1下生产环境Keepalived+Nginx配置 [日期:2015-07-20] 来源:Linux社区  作者:soulful [字体:大 中 小]   注:下文涉及到配置的,如无特别 ...

  7. require.js+backbone 使用r.js 在本地与生产环境 一键压缩的实现方式

    require.js+backbone 使用r.js 在本地与生产环境 一键压缩的实现方式 时间:2017-07-03 17:18:11      阅读:210      评论:0      收藏:0 ...

  8. 生产环境常见的HTTP状态码列表

    生产环境常见的HTTP状态码列表(List of HTTP status codes)为: 200 - OK,服务器成功返回网页     - Standard response for success ...

  9. 理解Docker(6):若干企业生产环境中的容器网络方案

    本系列文章将介绍 Docker的相关知识: (1)Docker 安装及基本用法 (2)Docker 镜像 (3)Docker 容器的隔离性 - 使用 Linux namespace 隔离容器的运行环境 ...

  10. .Net Core Linux centos7行—发布程序到生产环境

    实验demo现在需要发布到生产环境,发现在发布的时候要考虑到不一致的几个地方. 1.各类配置文件线下,线上不一致. 2.绑定的url不一致,可能是域名不一致,也可能是schema不一致(http,ht ...

随机推荐

  1. Nuxt Kit 实用工具的使用示例

    title: Nuxt Kit 实用工具的使用示例 date: 2024/9/25 updated: 2024/9/25 author: cmdragon excerpt: 摘要:本文介绍了Nuxt ...

  2. AE cc 2017 和 2018 中英文切换的方法

    AE cc 2017中文切换英文的方法 找到AE的安装文件目录下的"Support Files"文件夹,路径为 C:\Program Files\Adobe\Adobe After ...

  3. 【赵渝强老师】Redis的消息发布与订阅

    Redis 作为一个publish/subscribe server,起到了消息路由的功能.订阅者可以通过subscribe和psubscribe命令向Redis server订阅自己感兴趣的消息类型 ...

  4. 2021年3月国产数据库排行榜:OceanBase勇夺亚军 神舟挺进20强!

    1 新春排行 2021年3月榜单新鲜出炉,同2月相比,本月榜单中十强产品还是原来的面孔,其中3款产品取得了新的名次,榜单座次调整超过半数.前三甲仍然是TiDB.OceanBase.达梦. 冠军:TiD ...

  5. 基于 Nginx 的大型互联网集群架构与实战方案

    1. Nginx 负载均衡基础配置 首先,搭建一个基础的 Nginx 负载均衡器,用于将流量分发到多个后端服务器上. 步骤 1.1:安装 Nginx 在每台要作为负载均衡器的服务器上,安装 Nginx ...

  6. 从Windows 11 23H2升级至24H2后,Git操作提示文件所有权错误的3种有效解决方案

    从Windows 11 23H2升级至24H2后,Git操作提示文件所有权错误的3种有效解决方案 在升级至 Windows 11 24H2 后,使用 git add 等命令时,可能会遇到如下错误提示: ...

  7. vue3+tpyeScript + element plus 三级复选框,全选控制全部,左侧选中控制右侧全选

    .markdown-body { line-height: 1.75; font-weight: 400; font-size: 16px; overflow-x: hidden; color: rg ...

  8. 游戏推荐业务中基于 sentinel 的动态限流实践

    作者:来自 vivo 互联网服务器团队- Gao Meng 本文介绍了一种基于 sentinel 进行二次开发的动态限流解决方案,包括什么是动态限流.为什么需要引入动态限流.以及动态限流的实现原理. ...

  9. 《使用Gin框架构建分布式应用》阅读笔记:p77-p87

    <用Gin框架构建分布式应用>学习第5天,p77-p87总结,总计11页. 一.技术总结 1.Go知识点 (1)context 2.on-premises software p80, A ...

  10. 自学PHP笔记(一)PHP语法

    PHP基本语法 php使用一对特殊的标记包含php代码,与HTML代码混在一起.当服务器解析页面时,能够自动过滤出PHP脚本并进行解释,最后把生成的静态网页传递给客户端. 1.PHP标记 一般情况下, ...