bigdecimal.divide() 不指定 scale 和 roundingmode 会抛 arithmeticexception,因设计上拒绝隐式舍入;必须用三参数版本并合理设置 scale(如6)和 roundingmode.half_up。

为什么 BigDecimal.divide() 不指定参数就会炸
调用 divide() 时不传 scale 和 RoundingMode,只要结果是无限小数(比如 new BigDecimal("1").divide(new BigDecimal("3"))),就一定会抛 ArithmeticException: Non-terminating decimal expansion。这不是 bug,是设计使然——BigDecimal 拒绝“模糊精度”,宁可报错也不隐式舍入。
必须用三参数版本:divide(divisor, scale, roundingMode)
两参数或单参数版本都不可靠:
-
divide(BigDecimal divisor, RoundingMode mode):scale 默认取被除数的scale,而被除数的 scale 可能是 0(如new BigDecimal("1")),导致结果直接截成整数,业务上大概率错 -
divide(BigDecimal divisor):只适用于确定整除的场景(比如单位换算100分 =1元),其余情况基本必炸
正确写法只有这一种:amount.divide(rate, 6, RoundingMode.HALF_UP)。其中 6 是中间计算推荐的最小 scale(钱类计算建议至少留 4 位,利率类建议 6 位),RoundingMode.HALF_UP 是最通用的四舍五入模式。
选错 RoundingMode 会引发业务逻辑错误
不同舍入模式行为差异极大,不能凭直觉选:
-
RoundingMode.UNNECESSARY:要求必须整除,哪怕余数是0.0000001都抛异常,只适合校验,别用在常规计算 -
RoundingMode.DOWN:纯截断,不进位,适合计费系统里“向下取整收钱”,但用于税率会导致系统性少算 -
RoundingMode.UP:只要余数非零就进位,适合成本估算等“宁可高估”的场景 -
RoundingMode.HALF_EVEN(银行家舍入):统计场景更公平,但金融结算通常不用,客户看不懂“1.5 → 2,2.5 → 2”
绝大多数金融/财务代码应无条件用 RoundingMode.HALF_UP,它和人类习惯一致,也符合多数会计准则。
scale 设太小或为负是隐形炸弹
scale 必须是非负整数,否则直接抛 IllegalArgumentException;但它设得太小,问题更隐蔽:
- 设成
0:所有小数全砍掉,123.99.divide(new BigDecimal("100"), 0, RoundingMode.HALF_UP)得1,不是1.24 - 中间计算用
2位小数:比如算含税价时先除税率再乘税率,两次scale=2累积误差可能超 0.01 元 - 最终展示前才按需缩放:中间全程用高 precision(如
scale=6),最后用setScale(2, RoundingMode.HALF_UP)输出
真正容易被忽略的是:scale 不是“保留几位小数”的显示设置,而是参与计算的精度基底——它一旦定死,后续所有运算都受其约束,改起来牵一发而动全身。










