BigDecimal-使用new或valueOf


101

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

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

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

通常(不只是BigDecimal),建议使用什么-new或valueOf?

谢谢。


10
通常,首选valueOf(因为它可以避免通过重用“流行的”实例避免创建新对象),但是对于BigDecimals和double而言,不幸的是,这两种方法会产生不同的结果,因此您必须选择所需的一种。
Thilo

Answers:


163

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

对于BigDecimal:这有点棘手,因为他们做的不一样BigDecimal.valueOf(double)将使用规范String表示的的double在实例化传递的值BigDecimal对象。换句话说:BigDecimal对象的值将是您执行操作时看到的System.out.println(d)

new BigDecimal(d)但是,如果您使用,则BigDecimal将会尝试尽可能准确地表示该double值。通常,这将导致存储的位数超出您的期望。严格来说,它比正确,但直观性却差很多。valueOf()

JavaDoc中对此有一个很好的解释:

该构造函数的结果可能无法预测。有人可能会假设new BigDecimal(0.1)用Java 编写的代码会创建一个a BigDecimal,它等于0.1(未缩放的值1,小数位为1),但实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1无法精确地表示为double(或就此而言,表示为任何有限长度的二进制分数)。因此,尽管出现,但是传递给构造函数的值并不完全等于0.1。

通常,如果结果相同(即,在情况下不是BigDecimal,但在大多数其他情况下),valueOf()则应优先考虑:它可以缓存公用值(如上所示Integer.valueOf()),甚至可以更改缓存行为而无需呼叫者必须更改。即使没有必要,new也会始终实例化一个新值(最佳示例:new Boolean(true)vs Boolean.valueOf(true).)。



3
@Joachim,不清楚。是new BigDecimal()不是更好BigDecimal.valueOf()
ryvantage 2013年

5
@ryvantage:如果一个严格比另一个要好,那么两者都没有必要,我的答案会短很多。他们做的事情不一样,因此您不能像这样对他们进行排名。
Joachim Sauer 2013年

2
@JoachimSauer,好的,抱歉,我应该更具体一些。您介意给出何时new BigDecimal()首选的示例以及何时首选的示例BigDecimal.valueOf()吗?
ryvantage 2013年

@ryvantage:比较的结果new BigDecimal(1.0/30.0);BigDecimal.valueOf(1.0/30.0)。查看哪个结果实际上更接近数字分数1/30。
supercat

48

如果要使用BigDecimal对象存储货币值,则强烈建议您在计算时不要在任何地方涉及任何双精度值。

如另一个答案所述,存在双精度值的已知精度问题,这些问题会再次困扰您。

一旦超过了该限制,您的问题的答案就很简单。始终使用带有String值的构造函数方法作为构造函数的参数,因为没有valueOf方法String

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

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

另请参阅此相关问题


5

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

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

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

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


7
从技术上讲是正确的,但是:它将产生巨大的变化。valueOf()具有更直观的行为,而new BigDecimal(d)具有更正确的行为。尝试两者,看看有什么不同。
约阿希姆·绍尔

从技术上讲是错误的。“ new” Always关键字始终创建一个新对象,而javadoc不告诉valueOf是否总是返回一个新对象。并非总是如此。它在高速缓存中的一些值,从而new BigDecimal(1) != new BigDecimal(1)但是BigDecimal.valueOf(1) == BigDecimal.valueOf(1)
aalku

1
@user:是的,但既然BigDecimal是不可改变的,应当以相同方式处理的原始包装(IntegerByte,...),并String进行处理:对象的身份不应该不管你的代码中,只有价值应该的问题。
约阿希姆·绍尔

@Joachim对,但是内部缓存存在是有原因的。太多不必要的BigDecimal实例不是一件好事。我回答博士,他说“将创建一个新对象”
aalku 2011年

3
@user:是的,这就是为什么我说valueOf()应该通常是首选。但是请注意,BigDecimal.valueOf(double)它不进行任何缓存(也可能不值得)。
约阿希姆·绍尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.