You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

BigDecimal构造器类型差异导致JUnit断言成功/失败的原因

为什么BigDecimal构造器参数类型会影响JUnit断言结果?

核心原因是double类型的二进制浮点精度缺陷,这是Java浮点类型的固有问题,和JUnit本身无关。

两个构造器的本质区别

  • new BigDecimal(String s):会精确解析字符串中的十进制数值,完全复刻你输入的小数,得到的BigDecimal是严格精确的。比如new BigDecimal("2.55")就是实打实的2.55。
  • new BigDecimal(double d):会直接把double类型的二进制近似值转成BigDecimal。问题在于,很多十进制小数(比如2.55)无法用二进制浮点精确表示,存成double时已经是一个接近2.55但略有偏差的数值(实际是2.5500000000000000444089209850062616169452667236328125这类近似值),所以用这个构造器得到的BigDecimal根本不是你直观以为的2.55。

结合你的代码分析

你的计算逻辑里,除了spendingOne = new BigDecimal(0.25),其他都是用String构造的精确值。0.25之所以没问题,是因为它是2的负二次方,二进制可以精确表示,所以new BigDecimal(0.25)得到的是精确值。最终计算出来的finalBalance是精确的2.55。

当你用assertThat(finalBalance, is(new BigDecimal("2.55")))时,两边都是精确的2.55,自然断言通过。但用new BigDecimal(2.55)时,右边是那个带偏差的近似值,而BigDecimal的equals方法会同时比较数值和精度,两者不相等,断言就失败了。

解决方案

处理精确小数计算(比如货币、金额类场景)时,永远优先用String构造器创建BigDecimal。如果不得不从double转换,推荐用BigDecimal.valueOf(double)方法——它会先把double转成对应的十进制字符串再解析,得到的结果更符合直观预期。

比如把断言改成这样就能通过:

assertThat(finalBalance, is(BigDecimal.valueOf(2.55)));

附你提供的测试代码

断言通过的版本(String构造器)

@Test
public void areCalculationsDoingOkWithBigDecimal(){
    BigDecimal initialBalance = new BigDecimal(5);
    BigDecimal spendingOne = new BigDecimal(0.25);
    BigDecimal spendingTwo = new BigDecimal("0.47");
    BigDecimal spendingThree = new BigDecimal ("1.73");

    BigDecimal finalBalance = initialBalance.subtract(spendingOne).subtract(spendingTwo).subtract(spendingThree);

    System.out.println("Final balance after all the spendings: " + finalBalance);

    assertThat(finalBalance, is(new BigDecimal("2.55")));
}

断言失败的版本(double构造器)

@Test
public void areCalculationsDoingOkWithBigDecimal(){
    BigDecimal initialBalance = new BigDecimal(5);
    BigDecimal spendingOne = new BigDecimal(0.25);
    BigDecimal spendingTwo = new BigDecimal("0.47");
    BigDecimal spendingThree = new BigDecimal ("1.73");

    BigDecimal finalBalance = initialBalance.subtract(spendingOne).subtract(spendingTwo).subtract(spendingThree);

    System.out.println("Final balance after all the spendings: " + finalBalance);

    assertThat(finalBalance, is(new BigDecimal(2.55)));
}

内容的提问来源于stack exchange,提问作者CowOO

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 22:01:01