我发现有两种方法可以将double d转换为BigDecimal对象。
new BigDecimal(d)
BigDecimal.valueOf(d)
哪一种方法更好?valueOf
会创建一个新对象吗?
在一般情况下(不仅仅是BigDecimal),是建议使用new还是valueOf?
我发现有两种方法可以将double d转换为BigDecimal对象。
new BigDecimal(d)
BigDecimal.valueOf(d)
哪一种方法更好?valueOf
会创建一个新对象吗?
在一般情况下(不仅仅是BigDecimal),是建议使用new还是valueOf?
BigDecimal
?”和“一般情况下我该怎么做?”BigDecimal
:这有点棘手,因为它们没有做相同的事情。BigDecimal.valueOf(double)
将使用传入的double
值的规范化String
表示来实例化BigDecimal
对象。换句话说:当您执行System.out.println(d)
时,BigDecimal
对象的值将是您看到的值。new BigDecimal(d)
,那么BigDecimal
将尝试尽可能准确地表示double
值。这通常会导致存储比您想要的更多的数字。严格来说,它比valueOf()
更正确,但它不太直观。new BigDecimal(0.1)
会创建一个完全等于0.1的BigDecimal
(1的无标度值,比例为1),但实际上它等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1不能被精确地表示为一个double
(或者说任何有限长度的二进制小数)。因此,传递给构造函数的值并不完全等于0.1,尽管表面上看起来是这样的。BigDecimal
的情况下,而是在大多数其他情况下),则应该优先使用valueOf()
:它可以对常见的值进行缓存(如Integer.valueOf()
所示),甚至可以在不必更改调用者的情况下更改缓存行为。new
将始终实例化一个新值,即使不需要(最好的例子: new Boolean(true)
vs. Boolean.valueOf(true)
)。new BigDecimal()
比BigDecimal.valueOf()
更好吗? - ryvantagenew BigDecimal()
和何时应优先使用 BigDecimal.valueOf()
吗? - ryvantage如果您正在使用BigDecimal
对象来存储货币值,那么我强烈建议您在计算中不要涉及任何double值。
如另一个答案所述,double值存在已知的精度问题,而这些问题将会对您造成严重影响。
一旦您解决了这个问题,回答您的问题就很简单了。始终使用带有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
请参考这个相关问题
基本上,valueOf(double val) 只是这样做:
return new BigDecimal(Double.toString(val));
因此-> 是的,将创建一个新对象 :).
一般来说,我认为它取决于你的编码风格。如果两者结果相同,我不会混合使用 valueOf 和 "new"。
valueOf()
具有更直观的行为方式,而 new BigDecimal(d)
则更为正确。请尝试两者并比较差异。 - Joachim Sauernew BigDecimal(1) != new BigDecimal(1)
,但是 BigDecimal.valueOf(1) == BigDecimal.valueOf(1)
。 - aalkuBigDecimal
是不可变的,因此应该像原始包装器(Integer
,Byte
,...)和String
一样对待它:对象标识不应该对您的代码产生影响,只有值才应该受到关注。 - Joachim SauervalueOf()
通常 应该被优先选择的原因。但请注意,BigDecimal.valueOf(double)
不会进行任何缓存(而且也可能不值得这样做)。 - Joachim Sauernew BigDecimal(String val) or BigDecimal.valueOf(double val);
请勿使用:
new BigDecimal(double val);
为什么我们要讨论浮点类型、数字和算术?很简单,因为我们是按照十进制计数的,但机器是按照二进制计数的。
如果您正在使用 BigDecimal
,这意味着您需要精确表示 0.1
和其他负十次幂(通常涉及货币或小数运算)。
如果你发现自己需要使用BigDecimal
来操作double
(或float)类型的值,那么你就会遇到麻烦,因为在二进制中无法准确表示0.1
。机器将双精度浮点数(IEEE-754浮点算术标准)存储为二进制。这里有一篇很好的文章,如果你感兴趣可以了解一下。Duncan's answer阐述了我想说的做法和不做法。
任何你认为可以准确存储0.1的编程语言实际上都是近似值。
System.out.println(0.1d);
//Prints 0.1 or so you think ;-)
//If you are not convinced, try this:
double x = 1.1; double y = 1.0;
if (x-y == 0.1) {// print true } else {// print false}
//or perhaps this:
double amount1 = 2.15;
double amount2 = 1.10;
System.out.println("Difference: " + (amount1 - amount2));
double smallD = 0.0001;
double smallDNoScientificNotation = 0.001; //>= 10E-3
double normalD = 10.345678;
double bigDNoScientificNotation = 1234567.123456789; //<=10E7
double bigD = 56_789_123_456_789.123456789;
//double
System.out.println(smallD); //1.0E-4, computerized scientific notation, this is how Double toString works
System.out.println(smallDNoScientificNotation); //0.001, OK
System.out.println(normalD); //10.345678, OK
System.out.println(bigDNoScientificNotation); //1234567.123456789, OK
System.out.println(bigD); //5.6789123456789125E13, computerized scientific notation, this is how Double toString works
//new BigDecimal(double): not OK, don't use! Attempting to representing the base-2 representation as accurately as possible
System.out.println(new BigDecimal(smallD)); //0.000100000000000000004792173602385929598312941379845142364501953125
System.out.println(new BigDecimal(smallDNoScientificNotation)); //0.001000000000000000020816681711721685132943093776702880859375
System.out.println(new BigDecimal(normalD)); //10.34567799999999948568074614740908145904541015625
System.out.println(new BigDecimal(bigDNoScientificNotation)); //1234567.12345678894780576229095458984375
System.out.println(new BigDecimal(bigD)); //56789123456789.125
//BigDecimal.valueOf (Dont use if the range is >= 10E-3, >= 10E7), under the hood it's using Double.toString
System.out.println(BigDecimal.valueOf(smallD)); //0.00010 - notice the extra 0, stemming from 1.0E-4
System.out.println(BigDecimal.valueOf(smallDNoScientificNotation)); //0.001
System.out.println(BigDecimal.valueOf(normalD)); //10.345678
System.out.println(BigDecimal.valueOf(bigDNoScientificNotation)); //1234567.123456789
System.out.println(BigDecimal.valueOf(bigD)); //56789123456789.125 //loss of accuracy
计算机科学计数法 - 更多信息请点击此处。
条款60:如果需要精确答案,请避免使用float或double
浮点数和双精度类型不适合用于货币计算,因为无法准确地表示0.1(或任何其他负十次幂)作为浮点数或双精度数。
:
然而,使用BigDecimal有两个缺点:它比使用原始算术类型要麻烦得多,而且速度要慢得多。如果您正在解决单个简短的问题,则后者的缺点无关紧要,但前者可能会让您感到烦恼。
:
使用int或long作为BigDecimal的替代方案,具体取决于涉及的金额,并自行跟踪小数点。在这个例子中,显而易见的方法是以分为单位进行所有计算。