用了BigDecimal就不会资损?了解下BigDecimal这五个坑
Java后端技术
共 5236字,需浏览 11分钟
· 2022-08-02
往期热门文章:
1、一个依赖搞定 Spring Boot 反爬虫,防止接口盗刷!
BigDecimal
而导致故障的文章,但是除非在一些非常简单的场景,结算汇金类的业务也不会直接用BigDecimal
来计算金额,原因有两点:BigDecimal
里面还是有很多隐蔽的坑的BigDecimal
没有提供金额的单位
1. BigDecimal
中的五个容易踩的坑
1.1 new BigDecimal()
还是BigDecimal#valueOf()
?
BigDecimal bd1 = new BigDecimal(0.01);
BigDecimal bd2 = BigDecimal.valueOf(0.01);
System.out.println("bd1 = " + bd1);
System.out.println("bd2 = " + bd2);
bd1 = 0.01000000000000000020816681711721685132943093776702880859375
bd2 = 0.01
BigDecimal
的时候就已经丢精度了,而BigDecimal#valueOf
的实现却完全不同public static BigDecimal valueOf(double val) {
// Reminder: a zero double returns '0.0', so we cannot fastpath
// to use the constant ZERO. This might be important enough to
// justify a factory approach, a cache, or a few private
// constants, later.
return new BigDecimal(Double.toString(val));
}
BigDecimal
对象,因此避免了精度问题。所以大家要尽量要使用字符串而不是浮点数去构造BigDecimal
对象,如果实在不行,就使用BigDecimal#valueOf()
方法吧。1.2 等值比较
BigDecimal bd1 = new BigDecimal("1.0");
BigDecimal bd2 = new BigDecimal("1.00");
System.out.println(bd1.equals(bd2));
System.out.println(bd1.compareTo(bd2));
false
0
BigDecimal
中equals
方法的实现会比较两个数字的精度,而compareTo
方法则只会比较数值的大小。1.3 BigDecimal
并不代表无限精度
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("3.0");
a.divide(b) // results in the following exception.
java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
JVM
我们不需要返回精确的结果就好了BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("3.0");
a.divide(b, 2, RoundingMode.HALF_UP)// 0.33
1.4 BigDecimal
转回String
要小心
BigDecimal d = BigDecimal.valueOf(12334535345456700.12345634534534578901);
String out = d.toString(); // Or perform any formatting that needs to be done
System.out.println(out); // 1.23345353454567E+16
BigDecimal
有三个方法可以转为相应的字符串类型,切记不要用错:String toString(); // 有必要时使用科学计数法
String toPlainString(); // 不使用科学计数法
String toEngineeringString(); // 工程计算中经常使用的记录数字的方法,与科学计数法类似,但要求10的幂必须是3的倍数
1.5 执行顺序不能调换(乘法交换律失效)
BigDecimal a = BigDecimal.valueOf(1.0);
BigDecimal b = BigDecimal.valueOf(3.0);
BigDecimal c = BigDecimal.valueOf(3.0);
System.out.println(a.divide(b, 2, RoundingMode.HALF_UP).multiply(c)); // 0.990
System.out.println(a.multiply(c).divide(b, 2, RoundingMode.HALF_UP)); // 1.00
2. 最佳实践
BigDecimal
再封装一个Money
类,其实我们直接可以用一个半官方的Money
类:JSR 354 ,虽然没能在Java 9
中成为Java
标准,很有可能集成到后续的Java
版本中成为官方库。2.1 maven
坐标
<dependency>
<groupId>org.javamoney</groupId>
<artifactId>moneta</artifactId>
<version>1.1</version>
</dependency>
2.2 新建Money
类
CurrencyUnit cny = Monetary.getCurrency("CNY");
Money money = Money.of(1.0, cny);
// 或者 Money money = Money.of(1.0, "CNY");
//System.out.println(money);
2.3 金额运算
CurrencyUnit cny = Monetary.getCurrency("CNY");
Money oneYuan = Money.of(1.0, cny);
Money threeYuan = oneYuan.add(Money.of(2.0, "CNY")); //CNY 3
Money tenYuan = oneYuan.multiply(10); // CNY 10
Money fiveFen = oneYuan.divide(2); //CNY 0.5
2.4 比较相等
Money fiveFen = Money.of(0.5, "CNY"); //CNY 0.5
Money anotherFiveFen = Money.of(0.50, "CNY"); // CNY 0.50
System.out.println(fiveFen.equals(anotherFiveFen)); // true
BigDecimal
的一些坑。往期热门文章:
1、线上MySQL的自增id用尽怎么办?被面试官干趴下了! 2、计算机专业会不会成为下一个土木? 3、xxl-job惊艳的设计,怎能叫人不爱 4、ArrayList#subList这四个坑,一不小心就中招 5、面试官:大量请求 Redis 不存在的数据,从而影响数据库,该如何解决? 6、MySQL 暴跌! 7、超越 Xshell!号称下一代 Terminal 终端神器,用完爱不释手! 8、IDEA 官宣全新默认 UI,太震撼了!! 9、让你直呼「卧槽」的 GitHub 项目! 10、Kafka又笨又重,为啥不选Redis?
评论
老爸嘲讽我了,写破代码一年就挣十几万,他在工地带50个工人,一个月光人头费就3万,让我滚回去跟他干!
点击上方 "大数据肌肉猿"关注, 星标一起成长点击下方链接,进入高质量学习交流群今日更新| 1052个转型案例分享-大数据交流群来自:网络,侵删有个网友的父亲是做工程的,天天就嘲笑他,说他天天写着破代码有啥用,一年就拿个十多万的死工资,然后告诉他自己在工地里面带了50个工人,一个月能抽三万
程序源代码
0
微软开源MS-DOS操作系统源码,冲到GitHub第一了!
大家好,我是轩辕。这两天逛GitHub的时候,突然发现一个叫 MS-DOS的项目冲到Trending榜首了!定睛一看,微软官方啊,搜了一下才知道,原来前两天,微软把MS-DOS 4.0系统开源了!关于这个系统,估计现在很多程序员都不知道了,或者只在古老的教科书上看过这玩意儿。MS-DOS,全称为Mi
编程技术宇宙
6
多人同时导出 Excel 干崩服务器!新来的阿里大佬给出的解决方案太优雅了!
点击关注公众号,Java 干货及时推送↓推荐阅读:面试辅导,我们出大成果了!来源:juejin.cn/post/7259249904777838629前言 业务诉求:考虑到数据库数据日渐增多,导出会有全量数据的导出,多人同时导出可以会对服务性能造成影响,导出涉及到mysql查询的io操作,
Java技术栈
1
今年后端爆了???
大家好,我是二哥呀。每次登录牛客,看到最多的就是各种 Java 后端岗位的喜讯,美团 OC了、快手 OC 了、就连腾讯 OC 的都是 Java 岗,我怀疑牛客是不是给我打了“只报喜不报忧”的标签?星球里也有不少球友给我发来喜讯,难道说每年都在凉凉的 Java 后端又承担起了就业的重任?!不可能,绝对
沉默王二
3
BigDecimal 为什么可以保证精度不丢失?
来源:juejin.cn/post/7348709938023940136👉 欢迎加入小哈的星球 ,你将获得: 专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡 / 赠书福利全栈前后端分离博客项目 2.0 版本完结啦, 演示链接
小哈学Java
0
这五款牛逼的 IDEA 插件,堪称代码质量检查利器!
来源:blog.csdn.net/a745233700?type=blog一、Alibaba Java Coding Guidelines二、CheckStyle:三、PMD四、FindBugs:五、SonarLint:总结随着业务的发展,系统会越来越庞大,原本简单稳定的功能,可能在不断迭代后复杂度
码农突围
0
Java8 Steam流太难用了?那你可以试试 JDFrame
来源:juejin.cn/post/7356652717392740404👉 欢迎加入小哈的星球 ,你将获得: 专属的项目实战 / Java 学习路线 / 一对一提问 / 学习打卡 / 赠书福利全栈前后端分离博客项目 2.0 版本完结啦, 演示链接
小哈学Java
1
特斯拉大量毁约应届生offer?网友纷纷发帖“求收留”:毕业即失业,春招都快结束了……
点击上方 "大数据肌肉猿"关注, 星标一起成长点击下方链接,进入高质量学习交流群今日更新| 1052个转型案例分享-大数据交流群4月24日消息,特斯拉公司近期在全球范围内进行裁员,同时取消了许多应届毕业生的工作邀约(Offer),这一行为引起了广泛的讨论和关注。有不少网友在社交平台发帖称“
程序源代码
0