【问题标题】:BigDecimal - to use new or valueOfBigDecimal - 使用 new 或 valueOf
【发布时间】:2025-12-31 11:15:10
【问题描述】:

我遇到了两种从双 d 中获取 BigDecimal 对象的方法。

1. new BigDecimal(d)
2. BigDecimal.valueOf(d)

哪种方法更好? valueOf 会创建一个新对象吗?

一般来说(不仅仅是 BigDecimal),推荐什么 - new 或 valueOf?

谢谢。

【问题讨论】:

  • 一般而言,valueOf 是首选(因为它可以通过重用“流行”实例来避免生成新对象),但是在 BigDecimals 和 double 的情况下,不幸的是,这两种方法会产生不同的结果,所以你必须选择你需要的。

标签: java bigdecimal


【解决方案1】:

如果您使用 BigDecimal 对象来存储货币值,那么我强烈建议您不要在其计算中的任何位置涉及任何双精度值。

正如另一个答案中所述,双值存在已知的准确性问题,这些问题会再次困扰您。

一旦你克服了这个问题,你的问题的答案就很简单了。始终使用带有 String 值的构造函数方法作为构造函数的参数,因为 String 没有 valueOf 方法。

如果您想要证明,请尝试以下操作:

BigDecimal bd1 = new BigDecimal(0.01);
BigDecimal bd2 = new BigDecimal("0.01");
System.out.println("bd1 = " + bd1);
System.out.println("bd2 = " + bd2);

您将获得以下输出:

bd1 = 0.01000000000000000020816681711721685132943093776702880859375
bd2 = 0.01

另见related question

【讨论】:

    【解决方案2】:

    这是两个独立的问题:“BigDecimal 应该使用什么?”和“我一般会做什么?”

    对于BigDecimal:这有点棘手,因为他们不会做同样的事情BigDecimal.valueOf(double) 将使用传入的double 值的canonical String representation 来实例化BigDecimal 对象。换句话说:BigDecimal 对象的值将是您执行System.out.println(d) 时看到的值。

    如果您使用new BigDecimal(d),那么BigDecimal 将尝试尽可能准确地表示double。这通常会导致存储的数字比您想要的多得多。严格来说,它比valueOf() 更正确,但它的直观性要差很多。

    JavaDoc 中有一个很好的解释:

    此构造函数的结果可能有些不可预测。有人可能会假设在 Java 中编写 new BigDecimal(0.1) 会创建一个恰好等于 0.1 的 BigDecimal(未缩放的值 1,缩放为 1),但它实际上等于 0.1000000000000000055511151231257827021181583404541015625。这是因为 0.1 不能完全表示为 double(或者,就此而言,不能表示为任何有限长度的二进制分数)。因此,传递给构造函数的值并不完全等于 0.1,尽管看起来如此。

    一般来说,如果结果是一样的(即不是BigDecimal的情况,而是在大多数其他情况下),那么valueOf()应该是首选的:它可以做缓存公共值(如Integer.valueOf() 所示),它甚至可以更改缓存行为,而无需更改调用者。 new总是实例化一个新值,即使没有必要(最好的例子:new Boolean(true)Boolean.valueOf(true))。

    【讨论】:

    • 这也解释了我的问题:*.com/questions/15685705/…
    • @Joachim,不清楚。 new BigDecimal()BigDecimal.valueOf() 好吗?
    • @ryvantage:如果一个严格比另一个好,那么两者都不需要,我的回答会短得多。他们不做同样的事情,所以你不能这样对他们进行排名。
    • @JoachimSauer,好的,抱歉,我应该更具体一些。您介意举例说明何时首选new BigDecimal() 以及何时首选BigDecimal.valueOf()
    • @BrianKnoblauch:具有讽刺意味的是,“新”实际上更接近地匹配输入双精度,并且通过切断正确但不需要区分双精度值与下一个。
    【解决方案3】:

    基本上 valueOf(double val) 就是这样做的:

    return new BigDecimal(Double.toString(val));

    因此 -> 是的,将创建一个新对象:)。

    总的来说,我认为这取决于您的编码风格。如果两者的结果相同,我不会混淆 valueOf 和“new”。

    【讨论】:

    • 技术上是正确的,但是:它会产生巨大的不同。 valueOf() 的行为更直观,而new BigDecimal(d) 的行为更正确。两者都试一下,看看有什么不同。
    • 技术上是错误的。 'new' always 关键字总是创建一个新对象,而 javadoc 不告诉 valueOf 是否总是返回一个新对象。它没有,并非总是如此。它在缓存中有一些值,所以new BigDecimal(1) != new BigDecimal(1)BigDecimal.valueOf(1) == BigDecimal.valueOf(1)
    • @user: 是的,但由于BigDecimal 是不可变的,因此应该以与处理原始包装器(IntegerByte、...)和String 相同的方式处理: 对象身份对您的代码应该无关紧要,只有 才重要。
    • @Joachim 是的,但内部缓存的存在是有原因的。拥有太多不需要的 BigDecimal 相等实例并不是一件好事。我在回答博士,他说“将创建一个新对象”
    • @user:是的,这就是为什么我说valueOf()通常应该是首选。但请注意,BigDecimal.valueOf(double) 不做任何缓存(而且可能也不值得)。