前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >价格字段还用BigDecimal呢?我直接给你一拳。看看最新的Money类吧,下次给面试官吹牛逼有的讲!

价格字段还用BigDecimal呢?我直接给你一拳。看看最新的Money类吧,下次给面试官吹牛逼有的讲!

作者头像
程序员牛肉
发布于 2025-05-12 06:48:48
发布于 2025-05-12 06:48:48
8500
代码可运行
举报
运行总次数:0
代码可运行

大家好,我是程序员牛肉。

好久不见。最近在忙一些其他事情。没怎么更新文章。由此看来存货还是非常重要的。以后要慢慢地攒一些存货了。

今天在网上看文章的时候,发现好多人对于存储价格类的字段只知道BigDeciaml。

这可不太行啊。

首先我们要明白一点:BigDecimal本质上并不是设计专门用来存储货币字段的工具类。

BigDecimal是为了精确存储浮点数的,它是一个用来解决浮点误差的类。而只不过在价格字段中,我们对浮点误差比较敏感。所以才会大规模的使用BigDecimal来存储金融字段。

关于什么是浮点误差,可以读一下我的这一篇文章:

0.1+0.2还能不等于0.3,难道是计算机算错了?

2024-07-16

关于BigDecimal的实现机制解读,可以读一下我的这一篇文章:

面试官顶级细节拷打:你说说Java的BigDecimal是如何做到高精度运算的?

2025-01-12

简单来讲,BigDecimal在存储小数的时候,会把小数扩大N倍使其成为一个整数,并且保留相对应的精度信息。

而BigDecimal有一个很大的问题是:BigDecimal都是不可变的(immutable)的, 在进行每一次四则运算时,都会产生一个新的对象 ,所以在做加减乘除运算时要记得要保存操作后的值。

因此在频繁计算的场景下,会产生大量的垃圾对象。给线上服务器来带不小的压力。

而且由于BigDecimal有精度的概念,导致很多开发者一不注意就被坑了。最经典的问题就是混用CompareTo方法和equals方法导致的线上事故。

既然BigDecimal的有这么多坑点,那有没有更优秀的解决方案呢?

有的有的兄弟。Hutool就有专门的工具Money类来处理金钱字段。对应的Maven地址为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<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字段因为有了币种的概念,使得其操作更加自由。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 构造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的比例来分配一笔收入,就传入以下参数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Money income = new Money("1000.00");
// 平台:商家:推广方 = 3:3:4
Money[] distribution = income.allocate(new long[]{3, 3, 4});

这个设计思路也很简单,首先计算比例总和并按比例分配大部分金额,再通过余数处理将剩余金额顺序分配到前几位,既保证了分配结果的准确性又维持了总金额不变。

其设计巧妙之处在于使用纯整数运算避免浮点误差,通过三次简洁的遍历完成复杂比例分配,同时保持货币单位一致性,是处理金融分配场景的高效可靠方案。

那今天的文章就聊到这里了。相信通过我的介绍,你已经大致了解了Money工具类的设计思路。希望我的文章可以帮到你。

其实就从源码来看,它相比较于BigDecimal来讲最重要的优化就是提出了“币种”的概念。以此节省了很多不必要的操作。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-05-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员牛肉 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档