BigDecimal - new veya valueOf kullanmak için


101

Çift d'den BigDecimal nesnesini elde etmenin iki yolu ile karşılaştım.

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

Hangisi daha iyi bir yaklaşım olabilir? ValueOf yeni bir nesne yaratır mı?

Genel olarak (sadece BigDecimal değil), önerilen nedir - new veya valueOf?

Teşekkürler.


10
Genel olarak, valueOf tercih edilir (çünkü "popüler" örnekleri yeniden kullanarak yeni nesneler oluşturmaktan kaçınabilir), ancak BigDecimals ve double durumunda, ne yazık ki, iki yöntem farklı sonuçlar üretir, bu nedenle hangisine ihtiyacınız olduğunu seçmeniz gerekir.
Thilo

Yanıtlar:


165

Bunlar iki ayrı soru: "Ne için kullanmalıyım BigDecimal?" ve "Genel olarak ne yapmalıyım?"

Çünkü BigDecimal: bu biraz aldatıcı çünkü aynı şeyi yapmıyorlar . BigDecimal.valueOf(double)kullanacak kanonik Stringtemsil arasında doubleörneğini geçirilen değeri BigDecimalnesnesi. Başka bir deyişle: BigDecimalNesnenin değeri, yaptığınız zaman gördüğünüz şey olacaktır System.out.println(d).

new BigDecimal(d)Ancak kullanırsanız BigDecimal, doubledeğeri olabildiğince doğru bir şekilde temsil etmeye çalışacaktır . Bu genellikle istediğinizden çok daha fazla rakamın depolanmasına neden olur. Açıkçası, bundan daha doğru valueOf()ama çok daha az sezgisel.

JavaDoc'ta bunun güzel bir açıklaması var:

Bu kurucunun sonuçları bir şekilde tahmin edilemez olabilir. new BigDecimal(0.1)Java'da yazmanın BigDecimaltam olarak 0.1'e eşit olan bir a oluşturduğu varsayılabilir (ölçeklenmemiş 1 değeri, 1 ölçeği), ancak aslında 0.100000000000000000055511151231257827021181583404541015625'e eşittir. Bunun nedeni, 0.1'in tam olarak bir double(veya bu nedenle, herhangi bir sonlu uzunluğun ikili bir kesri) olarak temsil edilememesidir . Bu nedenle, kurucuya iletilen değer, görünüşe bakılmaksızın tam olarak 0.1'e eşit değildir.

Genel olarak, sonuç aynıysa (yani durumunda değil BigDecimal, ancak diğer birçok durumda), o valueOf()zaman tercih edilmelidir: ortak değerlerin önbelleğe alınmasını sağlayabilir (üzerinde görüldüğü gibi Integer.valueOf()) ve hatta önbelleğe alma davranışını değiştirmeden bile değiştirebilir. arayanın değiştirilmesi gerekiyor. newolacak hep , olmasa bile gerekli (: En iyi örnek yeni bir değer örneğini new Boolean(true)vs Boolean.valueOf(true)).


Bu aynı zamanda sorumu açıklıyor: stackoverflow.com/questions/15685705/…
Christian

3
@Joachim, net değildi. Daha mı new BigDecimal()iyi BigDecimal.valueOf()?
ryvantage

5
@ryvantage: Biri diğerinden kesinlikle daha iyi olsaydı, ikisine de gerek kalmazdı ve cevabım çok daha kısa olurdu. Aynı şeyi yapmazlar, bu yüzden onları bu şekilde sıralayamazsınız.
Joachim Sauer

2
@JoachimSauer, tamam üzgünüm daha spesifik olmalıydım. Ne zaman new BigDecimal()tercih edileceğine ve ne zaman tercih edileceğine dair bir örnek BigDecimal.valueOf()verebilir misiniz?
ryvantage

@ryvantage: sonuçlarını karşılaştırın new BigDecimal(1.0/30.0);ve BigDecimal.valueOf(1.0/30.0). Hangi sonucun sayısal kesir 1 / 30'a aslında daha yakın olduğunu görün.
supercat

48

Eğer BigDecimalnesnelerinizi para birimi değerlerini saklamak için kullanıyorsanız , o zaman onların hesaplamalarında herhangi bir yerde herhangi bir çift değer KULLANMAMANIZI şiddetle tavsiye ederim .

Başka bir cevapta belirtildiği gibi, çift değerli bilinen doğruluk sorunları vardır ve bunlar size büyük bir zaman musallat olmaya geri dönecektir.

Bunu geçtikten sonra, sorunuzun cevabı basittir. Orada hiçbir her zaman olduğu gibi, kurucu bağımsız değişken olarak dize değeri ile yapıcı yöntemini kullanmak valueOfiçin bir yöntem String.

Kanıt istiyorsanız, aşağıdakileri deneyin:

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

Aşağıdaki çıktıyı alacaksınız:

bd1 = 0.01000000000000000020816681711721685132943093776702880859375
bd2 = 0.01

Ayrıca bu ilgili soruya bakın


5

Temelde valueOf (double val) bunu yapar:

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

Bu nedenle -> evet, yeni bir nesne oluşturulacak :).

Genel olarak kodlama tarzınıza bağlı olduğunu düşünüyorum. Her ikisi de aynı sonuçsa, valueOf ve "new" i karıştırmam.


7
Teknik olarak doğru, ancak : çok büyük bir fark yaratacak . daha doğru davranışa sahipken valueOf()daha sezgisel davranışa new BigDecimal(d)sahiptir . İkisini de deneyin ve farkı görün.
Joachim Sauer

Teknik olarak yanlış. 'new' always anahtar sözcüğü her zaman yeni bir nesne oluştururken javadoc, valueOf'un her zaman yeni bir nesne döndürüp döndürmeyeceğini söylemez. Her zaman değil. Önbellekte bazı değerler var new BigDecimal(1) != new BigDecimal(1)amaBigDecimal.valueOf(1) == BigDecimal.valueOf(1)
aalku

1
@user: beri evet, ama BigDecimaldeğişmez ilkel sarmalayıcıları (aynı şekilde ele alınmalıdır Integer, Byte, ...) ve Stringnesne kimliği: davranılır önemli değil gerektiğini kodunuzu, sadece değer bir önemi olmalıdır.
Joachim Sauer

@Joachim Doğru ama bu dahili önbelleğin bir nedeni var. BigDecimal'in ihtiyaç duyulmayan çok sayıda eşit örneği olması iyi bir şey değildir. Ve ben
Dr.'ye cevap veriyordum

3
@ kullanıcı: evet, bu yüzden genellikle tercih valueOf()edilmesi gerektiğini söyledim . Ancak bunun herhangi bir önbelleğe alma işlemi yapmadığını unutmayın (ve muhtemelen buna değmez). BigDecimal.valueOf(double)
Joachim Sauer
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.