首页 > 其他分享 >生产环境BigDecimal用错了,已哭晕在厕所。。。

生产环境BigDecimal用错了,已哭晕在厕所。。。

时间:2024-12-08 11:43:20浏览次数:4  
标签:用错 BigDecimal 打印 System println new 厕所 out

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

前言

在日常开发中,很多小伙伴喜欢用 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,打印,System,println,new,厕所,out
From: https://www.cnblogs.com/12lisu/p/18593223

相关文章

  • Java中金额处理选择详解:BigDecimal vs Long vs Double
    Java中金额处理选择详解:BigDecimalvsLongvsDouble金额处理是开发中非常重要的一部分,特别是在金融、电商等涉及交易的系统中。以下是对三种方式(BigDecimal、Long、Double)的详细分析,以及为什么推荐BigDecimal的原因。1.Double为什么不适合处理金额?1.1浮点数的精......
  • MySQL用错了,99%的人已中招
    在我们日常工作中,可能会经常使用MySQL数据库,因为它是开源免费的,而且性能还不错。在国内的很多公司中,经常被使用。但我们在MySQL使用过程中,也非常容易踩坑,不信继续往下看。今天这篇文章重点跟大家一起聊一聊使用MySQL的15个坑,希望对你会有所帮助。1查询不加where条件有些小......
  • BigDecimal 常用方法
    文章目录BigDecimal常用方法1.初始化BigDecimal2.创建BigDecimal对象3.BigDecimal类中定义好的常量4.BigDecimal值之间的转换5.取当前值的相反数、绝对值、幂函数、保留数值的精度6.BigDecimal之间的运算:加减乘除方法7.两数相除保留精度BigDecimal常用方法1.初......
  • Java BigDecimal 详解
     目录一、BigDecimal简介二、常用方法A、BigDecimal常用构造方法B、BigDecimal常用方法二、代码实现A、加减乘除1.创建两个BigDecimal对象2.BigDecimal相加3.BigDecimal相减4.BigDecimal相乘5.BigDecimal相除B、转换1.定义一个数值2.转换3.java.math.BigDeci......
  • java实际开发——涉及金额时使用的数据类型BigDecimal
    目录首先说结论,使用BigDecimal类。为什么不用其它的类型?(比如int、long、float、double)1、整型:2、浮点型:BigDecimal类基本数据类型与BigDecimal使用时的差别:1、创建2、+-*/3、比较标度(Scale)舍入模式首先说结论,使用BigDecimal类。为什么不用其它的类型?(比......
  • BigDecimal
    加减乘除计算首先对bigdecimal的初始化BigDecimalnum1=newBigDecimal(0.005);BigDecimalnum2=newBigDecimal(1000000);BigDecimalnum3=newBigDecimal(-1000000);//尽量用字符串的形式初始化BigDecimalnum12=newBi......
  • BigDecimal转换
    代码检测爆出代码质量:使用浮点数进行精确计算简单说就是不能用doule,不精确,要用BigDecimalBigDecimal是一个对象,它的加减乘除等都跟数字类型不一样,以下就是它的一些常用方法new一个BigDecimalBigDecimalnum1=newBigDecimal("0.12");输出结果add():相当于加a.add(b)相当于a+bBigDe......
  • Java API:BigDecimal
    JavaAPI:BigDecimal目录JavaAPI:BigDecimal1BigDecimal2示例1BigDecimalBigDecimal类使用户完全控制舍入行为。如果未指定舍入模式,并且无法表示确切的结果,则抛出异常;否则,可以通过向操作提供适当的MathContext对象来进行计算,以选择精度和舍入模式。在这两种情况下,都......
  • 专业智慧厕所解决方案,智慧公厕厂家@卓振思众
    在快节奏的城市生活中,公共设施的便捷性和舒适度成为了市民日常体验的重要组成部分。作为公共设施中的关键一环,厕所的智能化升级正在成为提升城市公共服务质量的重要趋势。智慧厕所,正以其先进的技术和人性化的设计,重新定义我们对公共卫生设施的期望。【卓振思众】高科技智能门......
  • 公司企业大楼智慧厕所建设步骤和技术要求@卓振思众
    针对公司企业大楼的智慧厕所建设,我们可以从多个方面入手,确保方案的全面性和实用性。以下是【卓振思众】给您提供的一些具体的建设步骤和技术要求:建设步骤‌规划和设计阶段‌:‌屋体设计‌:根据《城市公共厕所设计标准》CJJ14-2016,确定空间面积、外观和功能规划。‌智慧功能规......