BigDecimal.ROUND_HALF_UP 是“>=0.5×10⁻ˢᶜᵃˡᵉ 则进1”的舍入模式,需用字符串构造+setScale指定RoundingMode.HALF_UP,避免double精度丢失;scale为负时向左舍入(如-1→十位);比较应优先用compareTo或stripTrailingZeros()。

BigDecimal.ROUND_HALF_UP 是 Java 中最常用、也最容易被误解的舍入模式之一。它并非简单地“四舍五入”,而是在指定小数位后,对后续部分按“>=0.5 则进1”的规则处理——但关键在于:这个“0.5”是相对于当前保留位的最小单位而言的(即 0.5 × 10−scale)。要真正实现符合数学直觉的四舍五入并避免精度陷阱,必须同时控制好 scale(小数位数) 和 舍入模式,且不能依赖已过时的构造方法。
必须用 setScale() 显式指定 scale 和 roundingMode
不要使用已废弃的 BigDecimal(double) 构造函数(如 new BigDecimal(1.235)),它会因 double 二进制精度丢失导致原始值失真。正确做法是:
- 用字符串或整数构造 BigDecimal,确保数值精确无损
- 再调用
setScale(int newScale, RoundingMode.HALF_UP)(推荐用RoundingMode.HALF_UP替代过时的BigDecimal.ROUND_HALF_UP)
例如:
BigDecimal value = new BigDecimal("12.345");BigDecimal rounded = value.setScale(2, RoundingMode.HALF_UP); // 结果为 12.35
注意 scale 为负数时的“向左舍入”行为
当 scale 为负数时,舍入作用于小数点左侧——这常被忽略,却是控制整数级精度的关键:
立即学习“Java免费学习笔记(深入)”;
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
-
setScale(-1, RoundingMode.HALF_UP):舍入到十位(如 123 → 120,127 → 130) -
setScale(-2, RoundingMode.HALF_UP):舍入到百位(如 1234 → 1200,1250 → 1300)
原理是:-1 表示“以 101 = 10 为单位”,判断余数是否 ≥ 5(即是否 ≥ 单位的一半)。
避免常见误区:compareTo 与 equals 的陷阱
BigDecimal 的 equals() 会比较值和 scale(new BigDecimal("1.0").equals(new BigDecimal("1.00")) 返回 false),而 compareTo() 只比大小。在舍入后做相等判断时:
- 统一用
compareTo(BigDecimal.ZERO) == 0判断是否为零值 - 若需语义相等(忽略 scale 差异),用
compareTo(other) == 0 - 舍入后的结果应优先用
compareTo或stripTrailingZeros()后再比较
完整安全示例:带校验的四舍五入工具方法
以下是一个鲁棒的封装,处理空值、负 scale、并返回标准化结果:
public static BigDecimal roundHalfUp(BigDecimal value, int scale) {if (value == null) return null;
return value.setScale(scale, RoundingMode.HALF_UP).stripTrailingZeros();
}
调用示例:
roundHalfUp(new BigDecimal("99.999"), 2); // → 100.00 → strip 后为 100roundHalfUp(new BigDecimal("1234.5"), -1); // → 1230

















