BigDecimal - เพื่อใช้ new หรือ valueOf


102

ฉันเจอสองวิธีในการดึงวัตถุ BigDecimal ออกจาก d สองเท่า

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

จะเป็นแนวทางไหนดี มูลค่าของการสร้างวัตถุใหม่หรือไม่?

โดยทั่วไป (ไม่ใช่แค่ BigDecimal) สิ่งที่แนะนำ - new หรือ valueOf?

ขอบคุณ.


10
โดยทั่วไปแล้ว valueOf เป็นที่ต้องการ (เนื่องจากสามารถหลีกเลี่ยงการสร้างออบเจ็กต์ใหม่โดยใช้อินสแตนซ์ "ยอดนิยม" ซ้ำ) แต่ในกรณีของ BigDecimals และ double น่าเสียดายที่ทั้งสองวิธีให้ผลลัพธ์ที่แตกต่างกันดังนั้นคุณต้องเลือกวิธีที่คุณต้องการ
Thilo

คำตอบ:


166

คำถามสองข้อนี้แยกกัน: "ฉันควรใช้เพื่อBigDecimalอะไร" และ "ฉันทำอะไรโดยทั่วไป"

สำหรับBigDecimal: นี่คือบิตหากินเพราะพวกเขาไม่ได้ทำในสิ่งเดียวกัน BigDecimal.valueOf(double)จะใช้การแสดงค่าตามมาตรฐานStringของdoubleค่าที่ส่งผ่านเพื่อสร้างอินสแตนซ์ของBigDecimalวัตถุ ในคำอื่น ๆ : ค่าของวัตถุจะเป็นสิ่งที่คุณเห็นเมื่อคุณทำBigDecimalSystem.out.println(d)

ถ้าคุณใช้new BigDecimal(d)อย่างไรแล้วBigDecimalจะพยายามที่จะเป็นตัวแทนของdoubleความคุ้มค่าอย่างถูกต้องที่สุด นี้จะมักจะส่งผลให้เกิดมากขึ้นตัวเลขถูกเก็บไว้มากกว่าที่คุณต้องการ พูดอย่างเคร่งครัดถูกต้องมากกว่าvalueOf()แต่ใช้งานง่ายกว่ามาก

มีคำอธิบายที่ดีเกี่ยวกับสิ่งนี้ใน JavaDoc:

ผลลัพธ์ของตัวสร้างนี้อาจไม่สามารถคาดเดาได้บ้าง อาจสันนิษฐานได้ว่าการเขียนnew BigDecimal(0.1)ใน Java จะสร้างBigDecimalซึ่งมีค่าเท่ากับ 0.1 (ค่าที่ไม่ได้ปรับขนาดเป็น 1 โดยมีมาตราส่วนเป็น 1) แต่จริงๆแล้วมันเท่ากับ 0.1000000000000000055511151231257827021181583404541015625 เนื่องจาก 0.1 ไม่สามารถแทนค่าเป็น a double(หรือสำหรับเรื่องนั้นเป็นเศษส่วนไบนารีของความยาว จำกัด ใด ๆ ) ดังนั้นค่าที่ส่งผ่านไปยังตัวสร้างจึงไม่เท่ากับ 0.1 แน่นอนแม้ว่าจะปรากฏก็ตาม

โดยทั่วไปหากผลลัพธ์เหมือนกัน (เช่นไม่ใช่ในกรณีของBigDecimalแต่ในกรณีอื่น ๆ ส่วนใหญ่) valueOf()ควรเลือกใช้: สามารถแคชค่าทั่วไป (ตามที่เห็นInteger.valueOf()) และยังสามารถเปลี่ยนพฤติกรรมการแคชได้โดยไม่ต้อง ต้องเปลี่ยนผู้โทร newจะสร้างอินสแตนซ์ค่าใหม่เสมอแม้ว่าจะไม่จำเป็นก็ตาม (ตัวอย่างที่ดีที่สุด: new Boolean(true)กับBoolean.valueOf(true))


นอกจากนี้ยังอธิบายคำถามของฉัน: stackoverflow.com/questions/15685705/…
Christian

3
@ โจอาคิมพูดไม่ชัด จะnew BigDecimal()ดีกว่าBigDecimal.valueOf()ไหม?
ryvantage

5
@ryvantage: ถ้าอย่างใดอย่างหนึ่งดีกว่าอย่างเคร่งครัดก็ไม่จำเป็นต้องมีทั้งสองอย่างและคำตอบของฉันก็จะสั้นลงมาก พวกเขาไม่ได้ทำสิ่งเดียวกันดังนั้นคุณจึงไม่สามารถจัดอันดับได้
Joachim Sauer

2
@JoachimSauer โอเคขอโทษนะฉันควรเจาะจงมากกว่านี้ คุณช่วยยกตัวอย่างได้ไหมว่าเมื่อไรที่new BigDecimal()จะเป็นที่ต้องการและตัวอย่างของเวลาที่BigDecimal.valueOf()จะเป็นที่ต้องการ?
ryvantage

@ryvantage: เปรียบเทียบผลลัพธ์ของnew BigDecimal(1.0/30.0);และBigDecimal.valueOf(1.0/30.0). ดูว่าผลลัพธ์ใดอยู่ใกล้เศษส่วนตัวเลข 1/30 มากขึ้น
supercat

49

หากคุณใช้อBigDecimalอบเจ็กต์ของคุณเพื่อจัดเก็บค่าสกุลเงินฉันขอแนะนำอย่างยิ่งว่าคุณไม่ต้องเกี่ยวข้องกับค่าสองค่าใด ๆ ในการคำนวณ

ตามที่ระบุไว้ในคำตอบอื่นมีปัญหาความแม่นยำที่ทราบกันดีเกี่ยวกับค่าสองค่าและสิ่งเหล่านี้จะกลับมาหลอกหลอนคุณ

เมื่อคุณผ่านพ้นจุดนั้นมาได้คำตอบสำหรับคำถามของคุณก็ง่าย มักจะใช้วิธีการสร้างมูลค่า String เป็นอาร์กิวเมนต์ที่จะสร้างเป็นไม่มีวิธีการvalueOfString

หากคุณต้องการหลักฐานให้ลองทำดังต่อไปนี้:

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));

ดังนั้น -> ใช่วัตถุใหม่จะถูกสร้างขึ้น :)

โดยทั่วไปฉันคิดว่ามันขึ้นอยู่กับรูปแบบการเข้ารหัสของคุณ ฉันจะไม่ผสมค่าของและ "ใหม่" ถ้าทั้งสองผลลัพธ์เหมือนกัน


7
ในทางเทคนิคก็จริงแต่มันจะสร้างความแตกต่างอย่างมาก valueOf()มีมากขึ้นใช้งานง่ายพฤติกรรมในขณะที่new BigDecimal(d)มีมากขึ้นที่ถูกต้องอย่างใดอย่างหนึ่ง ลองทั้งสองอย่างและดูความแตกต่าง
Joachim Sauer

เป็นเท็จทางเทคนิค คีย์เวิร์ด 'new' จะสร้างอ็อบเจกต์ใหม่เสมอในขณะที่ javadoc ไม่ได้บอกว่า valueOf จะส่งคืนอ็อบเจกต์ใหม่เสมอหรือไม่ มันไม่ไม่เสมอไป มันมีค่าบางอย่างในแคชnew BigDecimal(1) != new BigDecimal(1)แต่BigDecimal.valueOf(1) == BigDecimal.valueOf(1)
aalku

1
@user: ใช่ แต่เนื่องจากBigDecimalจะไม่เปลี่ยนรูปมันควรจะได้รับการปฏิบัติเช่นเดียวกับที่ห่อดั้งเดิม ( Integer, Byte, ... ) และStringได้รับการรักษา: ตัวตนของวัตถุที่ไม่ควรเรื่องรหัสของคุณเพียงค่าควรเรื่อง
Joachim Sauer

@Joachim ถูกต้อง แต่แคชภายในนั้นมีเหตุผล จำนวนมากเกินไปไม่จำเป็นต้องมี BigDecimal เท่ากันไม่ใช่สิ่งที่ดี และฉันก็ตอบดรเขาบอกว่า "วัตถุใหม่จะถูกสร้างขึ้น"
aalku

3
@ ผู้ใช้: ใช่นั่นคือเหตุผลที่ฉันบอกว่าโดยทั่วไปvalueOf()ควรเป็นที่ต้องการ แต่โปรดทราบว่าไม่ได้ทำการแคชใด ๆ (และอาจจะไม่คุ้มค่าด้วย) BigDecimal.valueOf(double)
Joachim Sauer
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.