大家好,我是程序员牛肉。
好久不见。最近在忙一些其他事情。没怎么更新文章。由此看来存货还是非常重要的。以后要慢慢地攒一些存货了。
今天在网上看文章的时候,发现好多人对于存储价格类的字段只知道BigDeciaml。
这可不太行啊。
首先我们要明白一点:BigDecimal本质上并不是设计专门用来存储货币字段的工具类。
BigDecimal是为了精确存储浮点数的,它是一个用来解决浮点误差的类。而只不过在价格字段中,我们对浮点误差比较敏感。所以才会大规模的使用BigDecimal来存储金融字段。
关于什么是浮点误差,可以读一下我的这一篇文章:
关于BigDecimal的实现机制解读,可以读一下我的这一篇文章:
面试官顶级细节拷打:你说说Java的BigDecimal是如何做到高精度运算的?
简单来讲,BigDecimal在存储小数的时候,会把小数扩大N倍使其成为一个整数,并且保留相对应的精度信息。
而BigDecimal有一个很大的问题是:BigDecimal都是不可变的(immutable)的, 在进行每一次四则运算时,都会产生一个新的对象 ,所以在做加减乘除运算时要记得要保存操作后的值。
因此在频繁计算的场景下,会产生大量的垃圾对象。给线上服务器来带不小的压力。
而且由于BigDecimal有精度的概念,导致很多开发者一不注意就被坑了。最经典的问题就是混用CompareTo方法和equals方法导致的线上事故。
既然BigDecimal的有这么多坑点,那有没有更优秀的解决方案呢?
有的有的兄弟。Hutool就有专门的工具Money类来处理金钱字段。对应的Maven地址为:
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>5.8.26</version>
</dependency>
我们来讲解一些关于Money工具类重要的字段和方法来学习它的优点:
可以看到,Money类相比较于BigDecimal来说,多了一个币种的字段。这个字段实在是太重要了。
在跨国业务中,我们可能操作的金额字段既有人民币,又有美金。那你如果用BigDecimal的话,就有可能会忘记汇率的问题。
并且不同的货币的精度和单位是不一样的。例如日元就没有小数位的概念,而美金的最小单位是美分,人民币的最小单位是分。
而当你规定了币种字段之后,其实也就是在约定当前这个Money类所代表货币的精度和最小单位。
Money类在进行运算操作的时候,会先比较两个类的币种是否相同。
并且相比较于BigDecimal,Money
类确保相同金额和币种的货币只有一种表示形式。
例如new Money("10.5")
和new Money("10.50")
会被视为相等,而BigDecimal("10.5")
与BigDecimal("10.50")
因scale
不同导致不相等。
那Money是怎么存储数字以此来避免浮点误差呢?
简单的来讲,Money 类通过「最小金额单位整型存储」机制确保精度。
比如人民币的最小单位是分,那么当你传参数为2.5人民币的时候的时候,对应的代码就会自动存储250分。
基于这种形式,我们就确保了不会出现浮点误差。可以看到他其实和BigDecimal的思想是一样的,都是变成大数之后进行存储。
但是相比较于BigDecimal,Money字段因为有了币种的概念,使得其操作更加自由。
// 构造3元50分(人民币)
Money m1 = new Money(3, 50, CNY); // cent=3*100 +50=350 →3.50元
// 构造0元75分(美元)
Money m2 = new Money(0, 75, USD); // cent=75 →0.75美元
在四则运算上,Money也支持直接对原值进行修改。避免了BigDecimal在四则运算过程中大量产生垃圾对象的问题。
而且相比较于BigDecimal来讲,Money类也有更多关于金融类的个性化方法。例如它提供了金额的分配方法。
我们可以基于Allocate方法实现对制定金额的均分或者是按比例分配。
比如你如果想按照3:3:4的比例来分配一笔收入,就传入以下参数:
Money income = new Money("1000.00");
// 平台:商家:推广方 = 3:3:4
Money[] distribution = income.allocate(new long[]{3, 3, 4});
这个设计思路也很简单,首先计算比例总和并按比例分配大部分金额,再通过余数处理将剩余金额顺序分配到前几位,既保证了分配结果的准确性又维持了总金额不变。
其设计巧妙之处在于使用纯整数运算避免浮点误差,通过三次简洁的遍历完成复杂比例分配,同时保持货币单位一致性,是处理金融分配场景的高效可靠方案。
那今天的文章就聊到这里了。相信通过我的介绍,你已经大致了解了Money工具类的设计思路。希望我的文章可以帮到你。
其实就从源码来看,它相比较于BigDecimal来讲最重要的优化就是提出了“币种”的概念。以此节省了很多不必要的操作。
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有