setScale未指定舍入模式时默认使用ROUND_UNNECESSARY,若需舍入则抛出ArithmeticException;必须显式传入RoundingMode(如HALF_UP)才能实现四舍五入等业务所需舍入行为。

BigDecimal 的 setScale 方法默认不指定舍入模式时会抛出异常(如果原值小数位数多于目标精度),而**不指定舍入模式本身不会自动采用银行家舍入(HALF_EVEN)**——关键在于:你**必须显式传入 RoundingMode 参数**,否则编译不通过或运行时报 ArithmeticException。所谓“规避银行家舍入误差”,本质是避免误用 RoundingMode.HALF_EVEN(这是 BigDecimal 某些静态方法如 round() 的默认模式),而明确选择更符合业务场景的舍入方式,例如金融计算中广泛使用的 RoundingMode.HALF_UP。
正确调用 setScale 指定 HALF_UP
要确保使用传统四舍五入(即 0.5 向上进位),必须在 setScale 中同时指定新精度和 RoundingMode.HALF_UP:
-
错误写法:
bigDecimal.setScale(2)→ 编译失败(缺少 RoundingMode) -
正确写法:
bigDecimal.setScale(2, RoundingMode.HALF_UP) - 该调用将数值精确保留 2 位小数,且对第 3 位按“四舍五入”逻辑处理:0.125 → 0.13,0.124 → 0.12,0.1250001 → 0.13
为什么 HALF_UP 更适合银行/财务场景
银行家舍入(HALF_EVEN)在统计上更无偏,但不符合大众认知和多数会计规范。金融系统通常要求确定性、可预期的进位行为:
-
RoundingMode.HALF_UP:0.5 一律进位(如 1.5 → 2,−1.5 → −2) -
RoundingMode.HALF_EVEN:0.5 向偶数方向舍入(如 1.5 → 2,2.5 → 2,−1.5 → −2,−2.5 → −2) - 合同、账单、利息计算等需明确约定“四舍五入”,HALF_UP 是行业事实标准
常见陷阱与规避建议
实际开发中容易忽略的细节:
- 不要混用
setScale和round(MathContext):后者若用MathContext(2, RoundingMode.HALF_UP),其精度含义是“总有效位数”,不是小数位数,易导致意外截断 - 注意原始值精度来源:若 BigDecimal 来自 double 构造(如
new BigDecimal(0.1)),本身已有二进制浮点误差,应改用字符串构造:new BigDecimal("0.1") - 统一项目内舍入策略:建议封装工具方法,如
roundToTwoDecimal(BigDecimal val),内部固定调用setScale(2, RoundingMode.HALF_UP),避免散落各处的不一致调用
其他常用金融相关舍入模式
除 HALF_UP 外,根据业务规则还可选:
-
RoundingMode.DOWN:直接截断(向零靠近),适用于手续费封顶、最小计费单位限制 -
RoundingMode.UP:远离零进位,适用于保证金、预估费用等保守估算 -
RoundingMode.CEILING:向正无穷进位(负数也向上,即更接近正数),适用于负债类金额上取整 - 慎用
HALF_DOWN和HALF_EVEN,除非明确合同约定或监管要求

















