1.3 java面试题:在 Java 中,BigDecimal 如何比大小

在 Java 中,BigDecimal 是处理金额等精确数值的必用类型。关于它的大小比较,最核心、最正确的方法就是 compareTo()

面试官如果问这个问题,几乎一定会接着问 equals() 的陷阱。为了方便你记忆和回答,我直接给你一个**"铁律"**:

比较大小用 compareTo(),判断绝对相等用 compareTo() == 0,千万别用 equals()


1. 正确方法:compareTo()

compareTo() 方法返回一个 int 值,逻辑和其他的 Comparable 接口完全一致:

  • 返回 -1 :当前数值 小于 参数 (a < b)
  • 返回 0 :当前数值 等于 参数 (a == b)
  • 返回 1 :当前数值 大于 参数 (a > b)

代码示例:

java 复制代码
BigDecimal a = new BigDecimal("10.00");
BigDecimal b = new BigDecimal("10.0");

// 正确的比较方式
int result = a.compareTo(b);

if (result == 0) {
    System.out.println("a 等于 b"); // 这里会输出"等于"
} else if (result > 0) {
    System.out.println("a 大于 b");
} else {
    System.out.println("a 小于 b");
}

2. 🚨 面试必问陷阱:compareTo()equals() 的区别

这是面试中最常挖的坑。equals() 不仅比较数值,还比较"标度(scale)",即小数点后的位数。

java 复制代码
BigDecimal a = new BigDecimal("2.0");
BigDecimal b = new BigDecimal("2.00");

System.out.println(a.compareTo(b)); // 输出 0 (视为相等)
System.out.println(a.equals(b));   // 输出 false (因为 2.0 的位数和 2.00 不同)
  • compareTo() :只关心数学上的数值大小2.02.00 数学上完全相等,所以返回 0
  • equals() :先比较数值,再比较标度。由于 2.0(scale=1)和 2.00(scale=2)标度不同,直接判定为 false

结论equals() 主要用于集合类(如 HashMap 的键)的绝对匹配,绝对禁止用于金额的大小比较。


3. 使用 compareTo() 时的避坑指南

坑点一:不能直接拿它当布尔值用

初学者容易犯 if (a.compareTo(b)) 的错误,这是编译报错的。你必须显式地和 0 比较:

java 复制代码
// 错误 ❌
if (a.compareTo(b)) { }

// 正确 ✅
if (a.compareTo(b) > 0) { }  // 大于
if (a.compareTo(b) >= 0) { } // 大于等于

坑点二:一定要处理 null

在 MyBatis 从数据库查出来的字段,或者前端传参时,BigDecimal 极可能是 null。直接调用 compareTo 会抛出 NullPointerException

java 复制代码
// 安全的比较工具类写法
public static boolean isGreaterThan(BigDecimal a, BigDecimal b) {
    a = a == null ? BigDecimal.ZERO : a;
    b = b == null ? BigDecimal.ZERO : b;
    return a.compareTo(b) > 0;
}

坑点三:构造方式影响精度

千万不要用 new BigDecimal(0.1),因为浮点数本身不精确,会导致 BigDecimal 带有脏数据。推荐使用字符串构造或 valueOf

java 复制代码
// 推荐写法 ✅
BigDecimal a = new BigDecimal("10.00");
BigDecimal b = BigDecimal.valueOf(10.00);

4. 高频场景速记表(直接背下来)

业务需求 推荐代码 备注
判断 a 是否大于 b a.compareTo(b) > 0 最常用
判断 a 是否等于 b a.compareTo(b) == 0 千万不能用 equals
判断 a 是否小于等于 b a.compareTo(b) <= 0 -
判空后的默认值 a = (a == null ? BigDecimal.ZERO : a); 防止 NPE
与 0 比较 a.compareTo(BigDecimal.ZERO) > 0 判断是否正数

结合我们之前聊的 MyBatis,如果在 SQL 映射中需要处理金额字段的比较,强烈建议在 SQL 层面(如 WHERE amount > #{target})做,而不是把大量数据查出来后再用 Java 的 compareTo 做内存过滤,这样性能会更好。

另外两个关于 BigDecimal 的高频追问是:BigDecimal 是不可变类吗? 以及 divide() 方法在使用时要注意什么? 需要我继续为你展开讲讲这两个进阶考点吗? 😊