BigDecimal - untuk menggunakan new atau valueOf

101

Saya menemukan dua cara untuk mengeluarkan objek BigDecimal dari d ganda.

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

Pendekatan mana yang lebih baik? Akankah valueOf membuat objek baru?

Secara umum (bukan hanya BigDecimal), apa yang direkomendasikan - new atau valueOf?

Terima kasih.

Manish Mulani
sumber
10
Secara umum, valueOf lebih disukai (karena dapat menghindari pembuatan objek baru dengan menggunakan kembali instance "populer"), tetapi dalam kasus BigDecimals dan double, sayangnya, kedua metode tersebut menghasilkan hasil yang berbeda, jadi Anda harus memilih yang mana yang Anda perlukan.
Thilo

Jawaban:

163

Itu adalah dua pertanyaan terpisah: "Apa yang harus saya gunakan BigDecimal?" dan "Apa yang harus saya lakukan secara umum?"

Sebab BigDecimal: ini agak rumit, karena mereka tidak melakukan hal yang sama . BigDecimal.valueOf(double)akan menggunakan representasi kanonikString dari doublenilai yang diteruskan untuk membuat instance BigDecimalobjek. Dengan kata lain: Nilai BigDecimalobjek akan menjadi apa yang Anda lihat saat melakukannya System.out.println(d).

Jika Anda menggunakan new BigDecimal(d)bagaimanapun, maka BigDecimalakan mencoba untuk mewakili doublenilai seakurat mungkin . Ini biasanya akan menghasilkan lebih banyak digit yang disimpan daripada yang Anda inginkan. Sebenarnya, ini lebih benar daripada valueOf(), tapi itu kurang intuitif.

Ada penjelasan bagus tentang ini di JavaDoc:

Hasil konstruktor ini bisa jadi agak tidak terduga. Orang mungkin berasumsi bahwa menulis new BigDecimal(0.1)di Java membuat nilai BigDecimalyang sama persis dengan 0,1 (nilai tidak berskala 1, dengan skala 1), tetapi sebenarnya sama dengan 0,1000000000000000055511151231257827021181583404541015625. Ini karena 0,1 tidak dapat direpresentasikan persis sebagai a double(atau, dalam hal ini, sebagai pecahan biner dengan panjang berhingga). Dengan demikian, nilai yang diteruskan ke konstruktor tidak persis sama dengan 0,1, meskipun penampilan.

Secara umum, jika hasilnya sama (yaitu tidak dalam kasus BigDecimal, tetapi dalam kebanyakan kasus lain), maka valueOf()sebaiknya lebih disukai: ia dapat melakukan caching nilai-nilai umum (seperti yang terlihat di Integer.valueOf()) dan bahkan dapat mengubah perilaku cache tanpa pemanggil harus diganti. newakan selalu memberi contoh nilai baru, meskipun tidak perlu (contoh terbaik: new Boolean(true)vs. Boolean.valueOf(true)).

Joachim Sauer
sumber
Ini juga menjelaskan pertanyaan saya: stackoverflow.com/questions/15685705/…
Christian
3
@Joachim, itu tidak jelas. Apakah new BigDecimal()lebih baik dari BigDecimal.valueOf()?
ryvantage
5
@ryvantage: jika satu tempat lebih baik dari yang lain maka tidak akan ada kebutuhan untuk keduanya dan jawaban saya akan jauh lebih singkat. Mereka tidak melakukan hal yang sama, jadi Anda tidak bisa memberi peringkat seperti itu.
Joachim Sauer
2
@JoachimSauer, ok maaf saya seharusnya lebih spesifik. Maukah Anda memberi contoh kapan new BigDecimal()akan disukai dan contoh kapan BigDecimal.valueOf()akan disukai?
ryvantage
@ryvantage: Bandingkan hasil dari new BigDecimal(1.0/30.0);dan BigDecimal.valueOf(1.0/30.0). Lihat hasil mana yang sebenarnya lebih mendekati pecahan numerik 1/30.
supercat
48

Jika Anda menggunakan BigDecimalobjek untuk menyimpan nilai mata uang, saya sangat menyarankan agar Anda TIDAK melibatkan nilai ganda di mana pun dalam perhitungannya.

Seperti yang dinyatakan dalam jawaban lain, ada masalah akurasi yang diketahui dengan nilai ganda dan ini akan kembali menghantui Anda.

Setelah Anda melewatinya, jawaban atas pertanyaan Anda sederhana. Selalu gunakan metode konstruktor dengan nilai String sebagai argumen untuk konstruktor, karena tidak ada valueOfmetode untuk String.

Jika Anda ingin bukti, coba yang berikut ini:

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

Anda akan mendapatkan hasil sebagai berikut:

bd1 = 0.01000000000000000020816681711721685132943093776702880859375
bd2 = 0.01

Lihat juga pertanyaan terkait ini

DuncanKindekat
sumber
5

Pada dasarnya valueOf (double val) hanya melakukan ini:

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

Oleh karena itu -> ya, objek baru akan dibuat :).

Secara umum saya pikir itu tergantung pada gaya pengkodean Anda. Saya tidak akan mencampurkan valueOf dan "new", jika keduanya merupakan hasil yang sama.

DXTR66
sumber
7
Secara teknis benar, tetapi : itu akan membuat perbedaan besar . valueOf()memiliki perilaku yang lebih intuitif , sedangkan new BigDecimal(d)memiliki perilaku yang lebih benar . Cobalah keduanya dan lihat perbedaannya.
Joachim Sauer
Salah secara teknis. 'new' always keyword selalu membuat objek baru sedangkan javadoc tidak memberi tahu apakah valueOf akan selalu mengembalikan objek baru atau tidak. Tidak selalu demikian. Ini memiliki beberapa nilai dalam cache jadi new BigDecimal(1) != new BigDecimal(1)tetapiBigDecimal.valueOf(1) == BigDecimal.valueOf(1)
aalku
1
@user: ya, tapi karena BigDecimaladalah kekal itu harus diperlakukan dengan cara yang sama bahwa pembungkus primitif ( Integer, Byte, ...) dan Stringdiperlakukan: identitas objek seharusnya tidak peduli untuk kode Anda, hanya nilai harus peduli.
Joachim Sauer
@Joachim Benar tetapi cache internal itu ada karena suatu alasan. Terlalu banyak contoh BigDecimal yang sama yang tidak diperlukan bukanlah hal yang baik untuk dimiliki. Dan saya menjawab Dr., Dia berkata "sebuah objek baru akan dibuat"
aalku
3
@user: ya, itu sebabnya saya mengatakan bahwa valueOf()harus umumnya lebih disukai. Tetapi perhatikan itu BigDecimal.valueOf(double)tidak melakukan caching apa pun (dan mungkin juga tidak sepadan).
Joachim Sauer