2008-11-12 58 views
85

Tôi hiểu rằng BigDecimal được khuyến nghị thực hành tốt nhất để biểu diễn các giá trị tiền tệ trong Java. Bạn dùng gì? Có thư viện nào tốt hơn mà bạn thích sử dụng thay thế không?Trình bày các giá trị tiền tệ trong Java

+3

hãy xem [JSR 354] (http://jcp.org/en/jsr/detail?id=354) – yegor256

+1

Đây là một loại tiền tệ mà bạn có thể sao chép và mở rộng: http: // java-articles. info/articles /? p = 254 –

+0

Ngoài ra, hãy xem phần thực hiện tham chiếu của JSR-354 https: // github.com/JavaMoney/jsr354-ri – beat

Trả lời

74

BigDecimal tất cả các cách. Tôi đã nghe nói về một số folks tạo ra các lớp học Cash hoặc Money riêng của họ đóng gói một giá trị tiền mặt với tiền tệ, nhưng dưới da nó vẫn là một BigDecimal, có lẽ với BigDecimal.ROUND_HALF_EVEN làm tròn.

Edit: Như Don đề cập trong his answer, có dự án sourced mở như timeandmoney, và trong khi tôi khen ngợi các em cố gắng để ngăn chặn các nhà phát triển từ phải phát minh lại bánh xe, tôi chỉ không có đủ niềm tin vào một trước thư viện -alpha để sử dụng nó trong môi trường sản xuất. Bên cạnh đó, nếu bạn đào xung quanh dưới mui xe, bạn sẽ thấy they use BigDecimal too.

+4

+1. Chúng tôi đã quyết định thêm một lớp container cũng tiêu thụ một loại tiền tệ. Điều này có ích khi hiển thị các giá trị tiền tệ trong bảng. – dhiller

+1

Vâng, đó là một cách tiếp cận khá phổ biến và nó có ý nghĩa rất nhiều. Một điều trước tiên là khi bạn phải đối phó với Yên Nhật, vì họ không có một mệnh giá tiền tệ nhỏ như xu, vì vậy nó cần các quy tắc làm tròn riêng của nó. – ninesided

+3

@ninesided đưa ra một ví dụ tuyệt vời về lý do tại sao việc cuộn của riêng bạn lại là một câu trả lời không tốt. "Ồ, và nhân tiện, nó không hoạt động với $ CURRENCY_X." Đó là một dấu hiệu tốt cho thấy nó cũng không hiệu quả với nhiều loại tiền tệ khác. –

3

BigDecimal hoặc một đại diện điểm cố định khác là thông thường cần thiết cho tiền.

Dấu chấm động (Double, Float) biểu diễn và tính toán không chính xác, dẫn đến kết quả sai.

+7

Nói đúng, BigDecimal cũng không chính xác; nó chỉ tương ứng tốt hơn với phép làm tròn thập phân mà chúng ta thường sử dụng trong cuộc sống hàng ngày và cho phép bạn chỉ định các chế độ làm tròn. –

+0

@Michael Borgwardt BigDecimal khác với IEEE FP ở quy mô rõ ràng được chỉ định. Mặc dù không phải tất cả các hoạt động đều chính xác, điều này đảm bảo rằng một tập hợp các hoạt động và hành vi là * luôn * chính xác và tỷ lệ là * hằng số * trong khi tỷ lệ cho IEEE FP giảm theo giá trị. –

+1

Điều đó có liên quan gì đến tiền? Các tổ chức kế toán trên khắp thế giới thường có những yêu cầu rất cụ thể về cách bạn làm toán bằng tiền của họ. BigDecimal có phù hợp chính xác với từng tiêu chuẩn này không? Nó sẽ làm như vậy vào năm tới, khi những tiêu chuẩn đó thay đổi? Và BigDecimal thậm chí không đến gần để xác định các quy tắc làm tròn hữu ích cho tiền tệ. –

7

Nếu bạn chỉ sử dụng đô la và xu, tôi sẽ sử dụng một khoảng thời gian dài (bù trừ 2 chữ số thập phân). Nếu bạn cần thêm chi tiết, số thập phân lớn có thể là cách để đi. Dù bằng cách nào, tôi có lẽ sẽ mở rộng lớp để có một .toString() sử dụng định dạng chính xác, và là một nơi để đưa các phương pháp khác có thể đi lên (Đối với một thời gian dài, nhân và chia sẽ đi awry nếu số thập phân không được điều chỉnh)

Ngoài ra, nếu bạn sử dụng xác định lớp và giao diện của riêng mình, thì bạn có thể thay thế triển khai theo ý muốn.

+2

Xem ra, thậm chí lâu dài có thể là quá ngắn để giữ nợ Liên bang Hoa Kỳ trong Cents ... nếu không phải bây giờ sau đó trong một vài năm. – Ingo

+3

Tôi đồng ý - bất kỳ số lượng lớn đô la (hoặc có thể nếu bạn đang theo dõi tiền trong Yên), bạn nên sử dụng BigDecimal - nhưng thậm chí sau đó tôi nghiêm túc xem xét sử dụng một lớp container cho nó. Tôi nghĩ rằng phần lớn sự phức tạp của lập trình xuất phát từ những người không định nghĩa các lớp nhỏ, đơn giản xung quanh các bộ sưu tập và các kiểu nội tại. –

2

Bạn phải cẩn thận khi xử lý thời gian và tiền bạc.

Khi bạn đang làm việc với tiền, tôi hy vọng mọi người nên biết không bao giờ sử dụng một phao hoặc một đôi.

Nhưng tôi không chắc chắn về BigDecimal.

Trong hầu hết các trường hợp, bạn sẽ ổn nếu bạn chỉ theo dõi xu trong một hoặc lâu. Bằng cách này bạn không bao giờ đối phó với một số thập phân.

Bạn chỉ hiển thị đô la khi in. Luôn luôn làm việc với xu nội bộ bằng cách sử dụng số nguyên. Điều này có thể phức tạp nếu cần chia hoặc cần sử dụng Math.abs().

Tuy nhiên, bạn có thể quan tâm đến nửa xu, hoặc thậm chí là một phần trăm của một xu. Tôi không biết cách tốt để làm điều này là gì. Bạn có thể chỉ cần đối phó với hàng ngàn xu và sử dụng một thời gian dài. Hoặc có thể bạn sẽ bị buộc phải sử dụng BigDecimal

Tôi sẽ đọc nhiều hơn về điều này, nhưng bỏ qua tất cả mọi người bắt đầu nói về việc sử dụng phao hoặc gấp đôi để đại diện cho tiền. Họ chỉ yêu cầu rắc rối.

Tôi cảm thấy lời khuyên của mình chưa hoàn chỉnh, vì vậy hãy đặt nhiều hơn vào nó. Bạn đang đối phó với các loại nguy hiểm!

+2

Tại sao bạn cần phải "buộc" để sử dụng BigDecimal? Bạn không chắc chắn về điều gì? Nó rõ ràng là tốt hơn để làm việc với xu, vì nó cho phép bạn xác định rõ ràng chế độ làm tròn. –

+1

@MichaelBorgwardt: vâng, nó cho phép bạn chỉ định một tập con nhỏ của các chế độ làm tròn bạn cần cho tiền tệ. Vì thế? (Gợi ý: tiền tệ làm tròn được quyết định, thông thường, bởi các tổ chức kế toán quốc gia. Họ hoàn toàn hạnh phúc để quăng trong trường hợp đặc biệt kỳ lạ. Xem http://stackoverflow.com/questions/5134237/swiss-and-argentinian-currency-fourth- chữ số thập phân làm tròn chỉ vì một trong nhiều lý do giải trí tại sao làm tròn BigDecimal hoàn toàn vô dụng ở đây.) –

+0

@James: Chính xác thì nó "vô ích" như thế nào? Làm thế nào để thực hiện các trường hợp đặc biệt này sẽ khó hơn với BigDecimal chứ không phải với cái gì khác? –

2

Tạo lớp Money là cách để thực hiện. Sử dụng BigDecimal (hoặc thậm chí là int) bên dưới. Sau đó sử dụng loại tiền tệ để xác định quy ước làm tròn.

Thật không may nếu không có quá tải toán tử Java khiến việc tạo các kiểu cơ bản như vậy khó chịu.

2

Có thư viện tốt hơn, timeandmoney. IMO, nó vượt trội hơn nhiều so với các thư viện do JDK cung cấp để biểu diễn 2 khái niệm này.

+3

Câu trả lời này đã được đăng cách đây ba năm. Hôm nay, dự án timeandmoney vẫn là pre-alpha theo liên kết đó. –

+1

@JamesMoore Cuộc gọi tốt.Câu trả lời bây giờ là 7 tuổi và dự án vẫn không ổn định. – Navin

1

Chắc chắn không phải BigDecimal. Có rất nhiều quy tắc đặc biệt để làm tròn và trình bày mà bạn phải lo lắng.

Martin Fowler khuyên bạn nên triển khai lớp chuyên dụng Money để đại diện cho số tiền và cũng thực hiện các quy tắc cho quy đổi tiền tệ.

+6

và loại dữ liệu cơ bản của lớp Money? BigDecimal. – ninesided

+1

Điều đó không đúng. Bạn có thể sử dụng Integer trong lớp tiền, đó là những gì Martin làm. Tôi đã làm việc này nhiều lần rồi. – egervari

+0

Đề xuất này là chính xác; tính toán liên quan đến tiền là một đầm lầy rộng lớn của các trường hợp đặc biệt thay đổi theo thời gian. BigDecimal có thể hữu ích như một phần nhỏ của giải pháp, nhưng nó chắc chắn không phải là chung. –

0

Bạn có thể sử dụng lớp DecimalFormat khi hiển thị giá trị tiền tệ. Nó cung cấp hỗ trợ bản địa hóa và có thể mở rộng được.

0

Tôi sẽ đóng gói BigDecimal trong lớp Money cũng có đơn vị tiền tệ giống như ai đó đã đề cập ở trên. Điều quan trọng là bạn làm một số lượng cực lớn các bài kiểm tra đơn vị và đặc biệt là nếu làm việc với các loại tiền tệ khác nhau. Ngoài ra nó là một ý tưởng tốt nếu bạn thêm một constructor thuận mà phải mất một chuỗi hoặc một phương pháp nhà máy mà không giống nhau để bạn có thể viết bài kiểm tra một cái gì đó của bạn như thế này:

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

Nó có thể có ích cho những người đến đây bởi các công cụ tìm kiếm để biết về JodaMoney: http://www.joda.org/joda-money/.

+0

Cảm ơn. Tôi đã có ý định thêm một lưu ý tiếp theo về tiền Joda. Bạn đã sử dụng nó chưa? – dshaw

+2

+1 có vẻ thú vị, vui mừng khi thấy nó là 'BigDecimal' dưới mui xe! – ninesided

1

Hey, đây là một bài viết rất thú vị về BigDecimal, và một ví dụ minh họa về lý do tại sao đôi khi nó được sử dụng thay vì tăng gấp đôi. BigDecimal Tutorial.

8

Thư viện tiện lợi mà tôi đã chạy trước đó là thư viện Joda-Money. Một trong những triển khai của nó thực sự dựa trên BigDecimal. Nó dựa trên đặc điểm ISO-4217 cho các loại tiền tệ và có thể hỗ trợ danh sách tiền tệ tùy chỉnh (được tải qua CVS).

Thư viện này có một số lượng tệp nhỏ mà người dùng có thể nhanh chóng thực hiện nếu cần sửa đổi. Joda-Money được xuất bản theo giấy phép Apache 2.0.

0

Luôn luôn có những khó khăn và chi tiết cụ thể có liên quan. Bất cứ ai mà không đủ kinh nghiệm để đánh giá cao những vấn đề tinh tế được nêu trong bài viết sau đây nên xem xét lại nghiêm túc trước khi giao dịch với các dữ liệu tài chính thực tế:

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

BigDecimal là hầu như không đại diện đúng chỉ hoặc mảnh duy nhất của câu đố. Với điều kiện nhất định, sử dụng một lớp Money được hỗ trợ bởi các xu được lưu trữ dưới dạng số nguyên có thể là đủ và sẽ nhanh hơn nhiều so với BigDecimal. Có, điều đó ngụ ý việc sử dụng đô la làm tiền và giới hạn số tiền nhưng những ràng buộc như vậy hoàn toàn có thể chấp nhận được cho nhiều trường hợp sử dụng và tất cả các loại tiền tệ có trường hợp đặc biệt để làm tròn và mệnh giá, vì vậy không có giải pháp "phổ quát".

+1

Điều này có vẻ là một nhận xét về bài đăng khác thay vì câu trả lời thực tế. Nó cũng quá nồng nhiệt. Hãy cố gắng trở nên dân sự hơn trong tương lai. –

+0

Điểm công bằng, được chỉnh sửa. – Craig

Các vấn đề liên quan