📋 目录
- 一、工具类功能
- 二、所需环境
- 三、方法与调用示例(按需调用)
- 四、工具类源码(可直接复制)
一、工具类功能
人民币金额的加减乘除、元分互转与千分位格式化一个类接住,全程走 BigDecimal 避开 double 直接运算的精度丢失,统一保留两位小数四舍五入、null 入参按 0 计。
二、所需环境
JDK 17或以上
三、方法与调用示例(按需调用)
🔢方法序号:1
🎯方法用途:
- 把多个金额一次加总,结果固定两位小数、四舍五入
- 全程走
BigDecimal,不用躲double相加掉精度,null元素按 0 计不用先过滤
🧩方法定义:public static BigDecimal add(BigDecimal... amounts)
🗣️入参解释:public static BigDecimal add(相加的多个金额)
📤返回值解释:BigDecimal,求和结果,不为null,标度恒为 2
💡边界口径:
- 元素为
null按 0 累加,数组本身传null是编程错误,抛IllegalArgumentException: 相加金额数组不能为null - 一个都不传、或全是
null,都得到0.00 - 结果标度恒为 2,第三位小数当场按四舍五入收掉,不会留到下游再决定
- 金额很大时用
long/int累加的溢出担忧在这里不存在
🧪方法示例:
add(new BigDecimal("10.00"), new BigDecimal("7.50"), null)拿到17.50add()一个都不传拿到0.00add(null, null)全是null元素拿到0.00add(new BigDecimal("0.001"), new BigDecimal("0.002"))拿到0.00,半分以下被收掉add(BigDecimal.ONE, BigDecimal.TEN)的scale()拿到2add((BigDecimal[]) null)抛IllegalArgumentException: 相加金额数组不能为null
🔢方法序号:2
🎯方法用途:
- 把可能是
null的金额兜成BigDecimal.ZERO,后续运算不用再判空 - 从数据库、报文里取出来的金额字段直接喂进加减乘除,不用每处写三元判断
🧩方法定义:public static BigDecimal nullToZero(BigDecimal amount)
🗣️入参解释:public static BigDecimal nullToZero(金额)
📤返回值解释:BigDecimal,非null的金额;入参不是null时原样返回
💡边界口径:
- 只兜
null,不改标度也不做舍入,非null的入参按同一个引用返回 - 兜出来的
BigDecimal.ZERO标度是 0,要两位小数得再setScale(2, HALF_UP) - 本类其它方法内部已经调它,单独用它只是为了让自己写的求和代码少一处判空
🧪方法示例:
nullToZero(null)拿到0,scale()是0,不是0.00nullToZero(new BigDecimal("3.14159"))拿到3.14159,一位没被收掉
🔢方法序号:3
🎯方法用途:
- 算两个金额的差(被减数减减数),结果两位小数、四舍五入
- 余额扣减、退款找差这类场景直接调,
null按 0 计
🧩方法定义:public static BigDecimal subtract(BigDecimal minuend, BigDecimal subtrahend)
🗣️入参解释:public static BigDecimal subtract(被减数, 减数)
📤返回值解释:BigDecimal,差值,标度恒为 2
💡边界口径:
- 两个入参都可以是
null,各按 0 计 - 结果可以是负数,扣超了不会替你把符号抹平
- 参数顺序是被减数在前、减数在后,写反了符号就反了
🧪方法示例:
subtract(new BigDecimal("100.00"), new BigDecimal("23.60"))余额扣减拿到76.40subtract(new BigDecimal("100"), new BigDecimal("123.75"))拿到-23.75,扣超了就是负数subtract(null, null)拿到0.00
🔢方法序号:4
🎯方法用途:
- 算两个金额(或金额与数量)的乘积,结果两位小数、四舍五入
- 单价乘数量、按比例算钱一行搞定,不用再手动
setScale
🧩方法定义:public static BigDecimal multiply(BigDecimal multiplier, BigDecimal multiplicand)
🗣️入参解释:public static BigDecimal multiply(乘数, 被乘数)
📤返回值解释:BigDecimal,乘积,标度恒为 2
💡边界口径:
- 任一入参为
null按 0 计,结果就是0.00 - 舍入发生在乘完之后:先把两位小之外的第三位按四舍五入收掉,不做两次舍入
- 数量类入参(比如
3、1.5)也当金额传,标度不影响结果
🧪方法示例:
multiply(new BigDecimal("1.3335"), new BigDecimal("5"))单价乘数量拿到6.67multiply(new BigDecimal("0.1"), new BigDecimal("0.2"))拿到0.02,double算法在这里会给0.020000000000000004multiply(null, BigDecimal.TEN)拿到0.00multiply(new BigDecimal("1.005"), BigDecimal.ONE)拿到1.01
🔢方法序号:5
🎯方法用途:
- 两个金额相除,默认保留两位小数、四舍五入
- 均摊、单价反算这类除法不用再包一层
setScale,除零也被转成说得清的异常
🧩方法定义:public static BigDecimal divide(BigDecimal dividend, BigDecimal divisor)
🗣️入参解释:public static BigDecimal divide(被除数, 除数)
📤返回值解释:BigDecimal,商,标度为 2
💡边界口径:
- 就是三参版把小数位数固定成 2 的入口
- 除数为 0 或为
null(按 0 计)抛IllegalArgumentException: 除数不能为 0,不会漏出 JDK 的ArithmeticException - 被除数为
null按 0 计,拿到0.00
🧪方法示例:
divide(new BigDecimal("100"), new BigDecimal("3"))百人均摊拿到33.33divide(BigDecimal.ONE, BigDecimal.ZERO)抛IllegalArgumentException: 除数不能为 0divide(null, BigDecimal.TEN)拿到0.00divide(BigDecimal.TEN, null)抛IllegalArgumentException: 除数不能为 0
🔢方法序号:6
🎯方法用途:
- 两个金额相除并自己指定保留几位小数
- 费率、单位成本这类要更多位数的商,不用为了多两位小数先放大再缩小
🧩方法定义:public static BigDecimal divide(BigDecimal dividend, BigDecimal divisor, int scale)
🗣️入参解释:public static BigDecimal divide(被除数, 除数, 小数位数)
📤返回值解释:BigDecimal,商,标度就是传入的小数位数
💡边界口径:
- 小数位数给 0 得到整数商,给负数抛
IllegalArgumentException: 小数位数不能为负: -1 - 除数为 0 同样抛
IllegalArgumentException,与位数无关 - 舍入仍是四舍五入,指定位数之外的部分被收掉
🧪方法示例:
divide(new BigDecimal("100"), new BigDecimal("3"), 6)拿到33.333333divide(new BigDecimal("1"), new BigDecimal("3"), 10)拿到0.3333333333divide(new BigDecimal("100"), new BigDecimal("3"), 0)拿到33,标度 0divide(BigDecimal.ONE, BigDecimal.TEN, -1)抛IllegalArgumentException: 小数位数不能为负: -1
🔢方法序号:7
🎯方法用途:
- 把元转成分,交回一个
long,正好对上银行和支付渠道按分传整数的约定 - 不足一分的部分四舍五入,进率固定 100,不用自己乘 100 再担心精度
🧩方法定义:public static long yuanToFen(BigDecimal yuan)
🗣️入参解释:public static long yuanToFen(金额(元))
📤返回值解释:long,金额(分)
💡边界口径:
- 金额为
null按 0 计,拿到0 - 四舍五入是离零方向的:
1.005元进成 101 分,-0.005元进成 -1 分 - 超出
long能表达的分数抛IllegalArgumentException,不会静默截断成别的数 - 结果是
long而不是BigDecimal,转完再想加总要注意精度口径
🧪方法示例:
yuanToFen(new BigDecimal("1.005"))拿到101分yuanToFen(new BigDecimal("1.004"))拿到100分yuanToFen((BigDecimal) null)拿到0yuanToFen(new BigDecimal("-0.005"))拿到-1yuanToFen(new BigDecimal("1E+20"))抛IllegalArgumentException,消息是「金额超出可表示范围(单位:分): 1E+20」
🔢方法序号:8
🎯方法用途:
- 直接把前端传来的金额文本转成分,跳过自己
new BigDecimal(...)这一步 - 表单里的
"128.50"、空字符串都能吃下,解不出来时说得清是哪段文本的问题
🧩方法定义:public static long yuanToFen(String yuanText)
🗣️入参解释:public static long yuanToFen(金额文本(元))
📤返回值解释:long,金额(分)
💡边界口径:
null、空串、全空白都按 0 计,拿到0- 文本先去掉首尾空白再解析,
1E+3这种科学计数法按BigDecimal的规则认,拿到100000分 - 带千分位逗号的文本(
1,234.5)不认,抛IllegalArgumentException;要处理展示串得先把逗号去掉 - 解析成功后的分数量级仍受
long约束,超限抛IllegalArgumentException
🧪方法示例:
yuanToFen("128.50")拿到12850分yuanToFen(" ")拿到0分,空串与null同样是0yuanToFen(" 128.50 ")拿到12850,首尾空白被去掉yuanToFen("1E+3")拿到100000yuanToFen("abc")抛IllegalArgumentException: 无法解析的金额文本: abcyuanToFen("1,234.5")抛IllegalArgumentException: 无法解析的金额文本: 1,234.5
🔢方法序号:9
🎯方法用途:
- 把渠道给的分数转回以元为单位的金额,两位小数
- 展示、入账前统一单位,不用自己
divide(100)还担心标度
🧩方法定义:public static BigDecimal fenToYuan(long fen)
🗣️入参解释:public static BigDecimal fenToYuan(金额(分))
📤返回值解释:BigDecimal,金额(元),标度恒为 2
💡边界口径:
- 进率固定 100,分数本来就是整数,这里不会出现舍入损失
- 负数照常转,
-1分就是-0.01元 - 入参是
long,分数量级超过long的数据应该在上游就拦住
🧪方法示例:
fenToYuan(12850L)拿到128.50fenToYuan(0L)拿到0.00,标度仍是 2fenToYuan(-1L)拿到-0.01fenToYuan(Long.MAX_VALUE)拿到92233720368547758.07
🔢方法序号:10
🎯方法用途:
- 分转元后直接交出两位小数的字符串,接口回包和页面渲染能直接用
- 免去
BigDecimal到字符串这一步,也不会被toString的科学计数法写法坑到
🧩方法定义:public static String fenToYuanText(long fen)
🗣️入参解释:public static String fenToYuanText(金额(分))
📤返回值解释:String,形如1.23的金额文本
💡边界口径:
- 内部就是
fenToYuan(fen).toPlainString(),永远不会出现E记数法 - 两位小数补齐,5 分是
"0.05"而不是"0.5" - 不带货币符号、不带千分位,要展示成对账单样子用方法11
🧪方法示例:
fenToYuanText(12850L)拿到128.50fenToYuanText(5L)拿到0.05,不足一位也补零
🔢方法序号:11
🎯方法用途:
- 把金额格式化成带千分位的展示串,固定两位小数、四舍五入
- 对账单、报表、小票这类要给人看的地方直接用它,输出不随 JVM 语言环境变
🧩方法定义:public static String formatThousands(BigDecimal amount)
🗣️入参解释:public static String formatThousands(金额)
📤返回值解释:String,千分位金额文本,分组符恒为逗号、小数分隔符恒为点号
💡边界口径:
- 数字符号固定按
Locale.ROOT,换成中文或德语语言环境跑,输出仍是逗号分组、点号小数 - 金额为
null按 0 计,拿到"0.00" - 小数第三位按四舍五入收掉,
1234567.891出来是"1,234,567.89" - 负数舍入到零时结果会是
"-0.00",展示前要判断的话记得这条
🧪方法示例:
formatThousands(new BigDecimal("1234567.891"))拿到1,234,567.89formatThousands(null)拿到0.00formatThousands(new BigDecimal("-9876543.217"))拿到-9,876,543.22formatThousands(new BigDecimal("1000"))拿到1,000.00,整数也补两位小数formatThousands(new BigDecimal("-0.004"))拿到-0.00
四、工具类源码(可直接复制)
📦领取方式: 关注点赞收藏,私信回复「java工具类」可领取100个工具类「Java企业级工具类全家桶(1-100)」的完整源码
💡 工具类已调试通过,复制粘贴即可使用,省时省力
💡 可保存到自己网盘,永久有效
觉得对您有帮助,麻烦点点关注啦,您的关注是我创作的最大动力~ 🎯