เป็นตัวแทนของค่าเงินใน Java [ปิด]


94

ฉันเข้าใจว่า BigDecimal แนะนำแนวทางปฏิบัติที่ดีที่สุดในการแสดงมูลค่าเงินใน Java คุณใช้อะไร? มีห้องสมุดที่ดีกว่าที่คุณต้องการใช้แทนหรือไม่?


4
ดูที่JSR 354
yegor256

1
นี่คือคลาสสกุลเงินหนึ่งที่คุณสามารถคัดลอกและขยายได้: java-articles.info/articles/?p=254
Gilbert Le Blanc

ดูการใช้งานอ้างอิงของ JSR-354 github.com/JavaMoney/jsr354-ri
ชนะ

คำตอบ:


81

BigDecimalทุกทาง. ฉันเคยได้ยินว่ามีคนบางคนสร้างของตัวเองCashหรือMoneyชั้นเรียนที่ห่อหุ้มมูลค่าเงินสดด้วยสกุลเงิน แต่ภายใต้ผิวหนังมันก็ยังคงBigDecimalมีBigDecimal.ROUND_HALF_EVENการปัดเศษ

แก้ไข: ดังที่ Don กล่าวถึงในคำตอบของเขามีโครงการโอเพ่นซอร์สเช่นเวลาและเงินและในขณะที่ฉันปรบมือให้พวกเขาที่พยายามป้องกันไม่ให้นักพัฒนาต้องสร้างวงล้อใหม่ฉันแค่ไม่มีความมั่นใจเพียงพอในไลบรารีก่อนอัลฟ่าที่จะใช้ ในสภาพแวดล้อมการผลิต นอกจากนี้หากคุณขุดไปรอบ ๆ ใต้ฝากระโปรงคุณจะเห็นว่าพวกเขาใช้BigDecimalเช่นกัน


4
+1. เราได้ตัดสินใจเพิ่มคลาสคอนเทนเนอร์ที่ใช้สกุลเงินด้วย สิ่งนี้มีประโยชน์เมื่อแสดงค่าเงินในตาราง
Daniel Hiller

1
ใช่นั่นเป็นแนวทางที่ใช้กันทั่วไปและเข้าท่ามาก ข้อแม้อย่างหนึ่งคือเมื่อคุณต้องจัดการกับเงินเยนของญี่ปุ่นเนื่องจากพวกเขาไม่มีสกุลเงินรองเช่นเซ็นต์ดังนั้นจึงต้องมีกฎการปัดเศษของตัวเอง
ninesided

3
@ninesided ให้ตัวอย่างที่ดีว่าทำไมการกลิ้งของคุณเองจึงเป็นคำตอบที่ไม่ดี "โอ้และยังไงก็ตามมันใช้ไม่ได้ในราคา $ CURRENCY_X" นั่นเป็นสัญญาณที่ดีว่ามันใช้ไม่ได้กับสกุลเงินอื่น ๆ
James Moore

1
@JamesMoore ฉันไม่เห็นด้วยที่การ "กลิ้งตัวเอง" เป็นแนวทางที่ไม่ดีคุณเพียงแค่ต้องตระหนักถึงข้อ จำกัด ที่เป็นไปได้ของแนวทางที่คุณเลือกดังนั้นเหตุผลที่ฉันกล่าวถึง เป็นเรื่องเล็กน้อยที่จะต้องใช้กฎการปัดเศษที่แตกต่างกันต่อสกุลเงิน แต่ถ้าระบบของคุณต้องการจัดการเป็น USD หรือ EUR คุณก็ไม่จำเป็นต้องทำอะไรมากกว่าวิศวกร
ninesided

1
ลองดูที่stackoverflow.com/questions/5134237/…ด้วยเหตุผลเดียวว่าทำไม BigDecimal จึงเป็นปัญหา การบัญชีทั่วโลกเป็นเพียงกรณีพิเศษมากมายและการพยายามกวาดล้างพวกเขาทั้งหมดภายใต้พรมของ BigDecimal ก็ไม่ได้ผล
James Moore

52

จะมีประโยชน์สำหรับผู้ที่มาที่นี่โดยเครื่องมือค้นหาที่ต้องการทราบเกี่ยวกับ JodaMoney: http://www.joda.org/joda-money/


ขอบคุณ. ฉันตั้งใจจะเพิ่มบันทึกติดตามผลเกี่ยวกับ Joda Money คุณเคยใช้หรือไม่
dshaw

2
+1 ดูน่าสนใจดีใจที่ได้เห็นมันBigDecimalอยู่ใต้ฝากระโปรง!
ninesided


8

ห้องสมุดที่สะดวกสบายที่ฉันพบก่อนหน้านี้คือห้องสมุดJoda-Money หนึ่งในการใช้งานนั้นขึ้นอยู่กับ BigDecimal เป็นไปตามข้อกำหนดISO-4217สำหรับสกุลเงินและสามารถรองรับรายการสกุลเงินที่กำหนดเองได้ (โหลดผ่าน CVS)

ไลบรารีนี้มีไฟล์จำนวนน้อยที่สามารถเข้าถึงได้อย่างรวดเร็วหากจำเป็นต้องมีการปรับเปลี่ยน Joda-Money เผยแพร่ภายใต้ลิขสิทธิ์ Apache 2.0


7

ถ้าคุณใช้แค่ดอลลาร์กับเซนต์ฉันจะใช้ long (ชดเชยด้วยทศนิยม 2 ตำแหน่ง) หากคุณต้องการรายละเอียดเพิ่มเติมทศนิยมใหญ่อาจเป็นวิธีที่จะไป

ไม่ว่าจะด้วยวิธีใดฉันอาจจะขยายคลาสให้มี. toString () ที่ใช้รูปแบบที่ถูกต้องและเป็นที่สำหรับใส่วิธีการอื่น ๆ ที่อาจเกิดขึ้น (เป็นเวลานานการคูณและการหารจะผิดปกติถ้าทศนิยมไม่ได้ ไม่ปรับ)

นอกจากนี้หากคุณใช้กำหนดคลาสและอินเทอร์เฟซของคุณเองคุณสามารถแทนที่การใช้งานได้ตามต้องการ


2
ระวังแม้ระยะเวลานานอาจสั้นเกินไปที่จะถือครองหนี้ของรัฐบาลกลางสหรัฐในหน่วยเซ็นต์ ... ถ้าไม่ใช่ตอนนี้ในอีกไม่กี่ปี
Ingo

3
ฉันเห็นด้วย - ดอลลาร์จำนวนมาก (หรือบางทีถ้าคุณติดตามเงินเป็นเยน) คุณควรใช้ BigDecimal - แต่ถึงอย่างนั้นฉันจะพิจารณาใช้คลาสคอนเทนเนอร์อย่างจริงจัง ฉันคิดว่าความซับซ้อนในการเขียนโปรแกรมส่วนใหญ่มาจากคนที่ไม่ได้กำหนดคลาสเล็ก ๆ ที่เรียบง่ายรอบคอลเลกชันและประเภทที่อยู่ภายใน
Bill K

3

BigDecimal หรือการแสดงจุดคงที่อีกแบบหนึ่งคือสิ่งที่จำเป็นโดยทั่วไปสำหรับเงิน

การแทนค่าและการคำนวณจุดลอยตัว ( Double, Float) ไม่ตรงทำให้ผลลัพธ์ที่ผิดพลาด


7
พูดอย่างเคร่งครัด BigDecimal ก็ไม่แน่นอนเช่นกัน มันสอดคล้องกับการปัดเศษทศนิยมที่เราคุ้นเคยในชีวิตประจำวันได้ดีขึ้นและช่วยให้คุณสามารถระบุโหมดการปัดเศษได้
Michael Borgwardt

1
@Michael Borgwardt BigDecimal แตกต่างจาก IEEE FP ตรงที่มีการระบุมาตราส่วนอย่างชัดเจน แม้ว่าการดำเนินการทั้งหมดจะไม่ถูกต้อง แต่ก็ช่วยให้มั่นใจได้ว่าชุดของการดำเนินการและพฤติกรรมจะถูกต้องเสมอและมาตราส่วนจะคงที่ในขณะที่มาตราส่วนสำหรับ IEEE FP จะลดลงตามค่า

1
เงินนั้นต้องทำอย่างไร? องค์กรบัญชีทั่วโลกมักจะมีข้อกำหนดที่เฉพาะเจาะจงมากสำหรับวิธีคำนวณทางคณิตศาสตร์ในสกุลเงินของตน BigDecimal ตรงกับมาตรฐานเหล่านี้หรือไม่ จะเป็นเช่นนั้นในปีหน้าเมื่อมาตรฐานเหล่านั้นเปลี่ยนไปหรือไม่? และ BigDecimal ไม่ได้ใกล้เคียงกับการระบุกฎการปัดเศษที่เป็นประโยชน์สำหรับสกุลเงิน
James Moore

2

คุณต้องระมัดระวังในการจัดการกับเวลาและเงิน

เมื่อคุณทำงานกับเงินฉันหวังว่าทุกคนควรรู้ว่าไม่ควรใช้โฟลตหรือสองเท่า

แต่ฉันไม่แน่ใจเกี่ยวกับ BigDecimal

ในกรณีส่วนใหญ่คุณจะสบายดีถ้าคุณติดตามเซ็นต์แบบ int หรือ long ด้วยวิธีนี้คุณจะไม่จัดการกับตำแหน่งทศนิยม

คุณจะแสดงเฉพาะดอลลาร์เมื่อคุณพิมพ์ ทำงานกับเซ็นต์ภายในโดยใช้จำนวนเต็มเสมอ อาจเป็นเรื่องยุ่งยากหากจำเป็นต้องหารหรือจำเป็นต้องใช้ Math.abs ()

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

ฉันจะอ่านเพิ่มเติมเกี่ยวกับเรื่องนี้ แต่อย่าสนใจทุกคนที่เริ่มพูดถึงการใช้ float หรือ double เพื่อแทนเงิน พวกเขาแค่ถามปัญหา

ฉันรู้สึกว่าคำแนะนำของฉันยังไม่สมบูรณ์ดังนั้นโปรดใส่ให้มากขึ้น คุณกำลังเผชิญกับประเภทอันตราย!


2
ทำไมคุณต้อง "บังคับ" ให้ใช้ BigDecimal? คุณไม่แน่ใจเกี่ยวกับอะไร มันเหนือกว่าการทำงานกับเซ็นต์อย่างชัดเจนเนื่องจากช่วยให้คุณระบุโหมดการปัดเศษได้อย่างชัดเจน
Michael Borgwardt

1
@MichaelBorgwardt: ใช่มันช่วยให้คุณระบุส่วนย่อยเล็ก ๆ ของโหมดการปัดเศษที่คุณต้องการสำหรับสกุลเงิน ดังนั้น? (คำแนะนำ: โดยปกติแล้วการปัดเศษสกุลเงินจะถูกตัดสินโดยองค์กรบัญชีระดับชาติพวกเขายินดีเป็นอย่างยิ่งที่จะโยนในกรณีพิเศษแปลก ๆ ดูstackoverflow.com/questions/5134237/…ด้วยเหตุผลที่น่าบันเทิงเพียงข้อเดียวที่ทำให้การปัดเศษ BigDecimal สมบูรณ์ ไม่มีประโยชน์ที่นี่)
James Moore

@ เจมส์: มัน "ไร้ประโยชน์" แค่ไหน? การใช้งาน thos กรณีพิเศษกับ BigDecimal จะยากกว่าอย่างอื่นอย่างไร
Michael Borgwardt

1
ตกลงไร้ประโยชน์อย่างสมบูรณ์แข็งแรงเกินไป ในคลาสที่ซับซ้อนซึ่งเป็นนามธรรมของสกุลเงินกฎการปัดเศษของ BigDecimal อาจมีประโยชน์ในบางกรณีในการสร้างชุดย่อยของวิธีการปัดเศษสกุลเงินที่เกิดขึ้น แต่กรณีทั่วไปก็คือกฎการปัดเศษสำหรับสกุลเงินจำเป็นต้องมีกลไกที่อาจเปลี่ยนแปลงได้ตลอดเวลา (เนื่องจากหน่วยงานบัญชีที่เป็นมนุษย์เป็นผู้สร้างกฎขึ้นมาและมีอิสระที่จะเปลี่ยนแปลงได้) คำถามไม่ได้เกี่ยวกับยูโร (หรืออะไรก็ตามที่แทนที่ยูโรในเดือนหน้า ... ) หรือดอลลาร์ในปี 2554 มันเกี่ยวกับสกุลเงินดังนั้นคุณต้องจัดการกับความซับซ้อนที่น่ารังเกียจมากมาย
James Moore

2

การสร้างคลาส Money คือหนทางที่จะไป ใช้ BigDecimal (หรือแม้แต่ int) ที่อยู่ข้างใต้ จากนั้นใช้คลาสสกุลเงินเพื่อกำหนดรูปแบบการปัดเศษ

น่าเสียดายที่ไม่มีตัวดำเนินการที่ใช้ Java มากเกินไปทำให้การสร้างประเภทพื้นฐานดังกล่าวค่อนข้างไม่สะดวก


2

มีห้องสมุดที่ดีกว่าคือtimeandmoney IMO ดีกว่าไลบรารีที่ JDK จัดเตรียมไว้สำหรับการแสดง 2 แนวคิดนี้


3
คำตอบนี้โพสต์เมื่อสามปีที่แล้ว วันนี้โครงการ timeandmoney ยังคงเป็น pre-alpha ตามลิงค์นั้น
James Moore

1
@JamesMoore ดีโทร. คำตอบคือตอนนี้ 7 ปีและโครงการยังไม่มั่นคง
นาวิน

1

ไม่ใช่ BigDecimal แน่นอน มีกฎพิเศษมากมายสำหรับการปัดเศษและการนำเสนอที่คุณต้องกังวล

Martin Fowler แนะนำให้ใช้คลาสMoneyโดยเฉพาะเพื่อแสดงจำนวนสกุลเงินและยังใช้กฎสำหรับการแปลงสกุลเงินอีกด้วย


6
และประเภทข้อมูลพื้นฐานของคลาส Money ของเขา? BigDecimal
ninesided

1
ที่ไม่เป็นความจริง. คุณสามารถใช้ Integer ในชั้นเงินซึ่งเป็นสิ่งที่ Martin ทำ ฉันทำแบบนี้หลายครั้งแล้ว
egervari

คำแนะนำนั้นถูกต้องแม้ว่า; การคำนวณเกี่ยวกับเงินเป็นกรณีพิเศษมากมายที่เปลี่ยนแปลงตลอดเวลา BigDecimal อาจมีประโยชน์ในฐานะส่วนเล็ก ๆ ของโซลูชัน แต่ก็ไม่ใช่เรื่องทั่วไป
James Moore


0

คุณสามารถใช้คลาส DecimalFormat เมื่อแสดงค่าสกุลเงินในท้ายที่สุด ให้การสนับสนุนการแปลเป็นภาษาท้องถิ่นและค่อนข้างขยายได้


0

ฉันจะห่อหุ้ม BigDecimal ในชั้น Money ซึ่งมีสกุลเงินเหมือนที่ใครบางคนกล่าวถึง สิ่งสำคัญคือคุณทำการทดสอบหน่วยจำนวนมากและโดยเฉพาะอย่างยิ่งหากทำงานกับสกุลเงินที่แตกต่างกัน นอกจากนี้ยังเป็นความคิดที่ดีหากคุณเพิ่มคอนสตรัคเตอร์ที่สะดวกซึ่งใช้สตริงหรือวิธีการจากโรงงานที่ทำเช่นเดียวกันเพื่อให้คุณสามารถเขียนการทดสอบของคุณได้ดังนี้:

   assertEquals(Money.create("100.0 USD").add("10 GBP"),Money.create("116 USD"));

0

มีข้อ จำกัด และข้อมูลเฉพาะที่เกี่ยวข้องเสมอ ใครก็ตามที่ไม่มีประสบการณ์เพียงพอที่จะเข้าใจประเด็นที่ละเอียดอ่อนที่ระบุไว้ในบทความต่อไปนี้ควรพิจารณาใหม่อย่างจริงจังก่อนจัดการกับข้อมูลทางการเงินในโลกแห่งความเป็นจริง:

http://lemnik.wordpress.com/2011/03/25/bigdecimal-and-your-money

BigDecimal แทบจะไม่ได้เป็นเพียงการนำเสนอที่ถูกต้องหรือเป็นเพียงส่วนเดียวของปริศนา ด้วยเงื่อนไขบางประการการใช้คลาส Money ที่ได้รับการสนับสนุนโดยเซ็นต์ที่จัดเก็บเป็นจำนวนเต็มอาจเพียงพอและจะเร็วกว่า BigDecimal มาก ใช่นั่นหมายถึงการใช้ดอลลาร์เป็นสกุลเงินและ จำกัด จำนวนเงิน แต่ข้อ จำกัด ดังกล่าวเป็นที่ยอมรับอย่างสมบูรณ์สำหรับกรณีการใช้งานจำนวนมากและทุกสกุลเงินก็มีกรณีพิเศษสำหรับการปัดเศษและนิกายย่อยอยู่แล้วดังนั้นจึงไม่มีโซลูชัน "สากล"


1
ดูเหมือนว่าจะเป็นการแสดงความคิดเห็นในโพสต์อื่นแทนที่จะเป็นคำตอบจริง นอกจากนี้ยังมีกรดด่างมากเกินไป โปรดพยายามที่จะเป็นพลเรือนมากขึ้นในอนาคต
Slater Victoroff
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.