Mewakili Nilai Moneter di Jawa [tutup]

94

Saya memahami bahwa BigDecimal direkomendasikan sebagai praktik terbaik untuk merepresentasikan nilai moneter di Jawa. Apa yang kamu gunakan? Apakah ada perpustakaan yang lebih baik yang lebih Anda pilih untuk digunakan?

dshaw
sumber
4
lihat JSR 354
yegor256
1
Inilah salah satu kelas Mata Uang yang dapat Anda salin dan kembangkan
Gilbert Le Blanc
Lihat juga implementasi referensi JSR-354 github.com/JavaMoney/jsr354-ri
kalahkan

Jawaban:

81

BigDecimalsepanjang perjalanan. Saya pernah mendengar tentang beberapa orang yang membuat kelas Cashatau mereka sendiri Moneyyang merangkum nilai tunai dengan mata uang, tetapi di baliknya itu masih BigDecimal, mungkin dengan BigDecimal.ROUND_HALF_EVENpembulatan.

Sunting: Seperti yang Don sebutkan dalam jawabannya , ada proyek bersumber terbuka seperti waktu dan uang, dan sementara saya memuji mereka karena mencoba mencegah pengembang dari keharusan menemukan kembali roda, saya hanya tidak cukup percaya pada perpustakaan pra-alfa untuk digunakan itu dalam lingkungan produksi. Selain itu, jika Anda menggali di bawah kap mesin, Anda akan melihat mereka BigDecimaljuga menggunakannya .

bersisi sembilan
sumber
4
+1. Kami telah memutuskan untuk menambahkan kelas kontainer yang menggunakan mata uang juga. Ini berguna saat merender nilai moneter dalam tabel.
Daniel Hiller
1
ya, itu pendekatan yang cukup umum dan sangat masuk akal. Satu peringatan untuk ini adalah ketika Anda harus berurusan dengan Yen Jepang, karena mereka tidak memiliki denominasi mata uang kecil seperti sen, jadi perlu aturan pembulatannya sendiri.
ninesided
3
@ninesided memberikan contoh yang bagus tentang mengapa menggulung milik Anda sendiri adalah jawaban yang buruk. "Oh, dan omong-omong, ini tidak berfungsi untuk $ CURRENCY_X." Itu pertanda baik bahwa itu juga tidak berfungsi untuk banyak mata uang lain.
James Moore
1
@JamesMoore Saya tidak setuju bahwa "menggulirkan milik Anda" adalah pendekatan yang buruk, Anda hanya perlu menyadari kemungkinan keterbatasan pendekatan yang Anda pilih, oleh karena itu alasan saya menyebutkannya. Sangat mudah untuk menerapkan aturan pembulatan yang berbeda untuk setiap mata uang, tetapi jika sistem Anda hanya perlu berurusan dengan USD atau EUR maka Anda tidak perlu terlalu banyak merekayasa sesuatu.
kesembilan
1
Lihatlah stackoverflow.com/questions/5134237/… untuk satu alasan mengapa BigDecimal menjadi masalah. Akuntansi di seluruh dunia hanyalah rawa dari kasus-kasus khusus, dan mencoba untuk menyapu semuanya ke bawah karpet BigDecimal tidak berhasil.
James Moore
52

Mungkin bermanfaat bagi orang yang tiba di sini melalui mesin telusur untuk mengetahui tentang JodaMoney: http://www.joda.org/joda-money/ .

Iñaki Ibarrola Atxa
sumber
Terima kasih. Saya ingin menambahkan catatan tindak lanjut tentang Joda Money. Apakah kamu sudah menggunakannya
dshaw
2
+1 terlihat menarik, senang melihatnya ada BigDecimaldi balik tenda!
kesembilan
8

Perpustakaan yang nyaman yang saya temui sebelumnya adalah perpustakaan Joda-Money . Salah satu implementasinya memang berdasarkan BigDecimal. Ini didasarkan pada spesifikasi ISO-4217 untuk mata uang dan dapat mendukung daftar mata uang yang disesuaikan (dimuat melalui CVS).

Pustaka ini memiliki sejumlah kecil file yang dapat dengan cepat melalui modifikasi jika diperlukan. Joda-Money diterbitkan di bawah lisensi Apache 2.0.

Bashar
sumber
7

Jika Anda hanya menggunakan dolar dan sen, saya akan menggunakan long (diimbangi dengan 2 tempat desimal). Jika Anda membutuhkan lebih banyak detail, desimal besar mungkin bisa menjadi cara yang tepat.

Either way, saya mungkin akan memperluas kelas untuk memiliki .toString () yang menggunakan format yang benar, dan sebagai tempat untuk meletakkan metode lain yang mungkin muncul (Untuk waktu yang lama, mengalikan dan membagi akan kacau jika desimal tidak disesuaikan)

Selain itu, jika Anda menggunakan define kelas dan antarmuka Anda sendiri, maka Anda dapat mengganti implementasi sesuka Anda.

Bill K
sumber
2
Hati-hati, bahkan lama bisa terlalu singkat untuk menahan Hutang Federal AS dalam Sen ... jika tidak sekarang maka dalam beberapa tahun.
Ingo
3
Saya setuju - sejumlah besar dolar (atau mungkin jika Anda melacak uang dalam Yen) Anda harus menggunakan BigDecimal - tetapi bahkan kemudian saya secara serius mempertimbangkan untuk menggunakan kelas kontainer untuk itu. Saya pikir sebagian besar kompleksitas pemrograman berasal dari orang-orang yang tidak mendefinisikan kelas-kelas kecil dan sederhana seputar koleksi dan tipe intrinsik.
Bill K
3

BigDecimal atau representasi titik tetap lainnya adalah apa yang umumnya dibutuhkan untuk uang.

Representasi dan kalkulasi floating point ( Double, Float) tidak tepat, yang menyebabkan hasil yang salah.

Ken Gentle
sumber
7
Sebenarnya, BigDecimal juga tidak tepat; itu hanya lebih sesuai dengan pembulatan desimal yang biasa kita lakukan dalam kehidupan sehari-hari, dan memungkinkan Anda menentukan mode pembulatan.
Michael Borgwardt
1
@Michael Borgwardt BigDecimal berbeda dari IEEE FP dalam skala eksplisit yang ditentukan. Meskipun tidak semua operasi tepat, ini memastikan bahwa satu set operasi dan perilaku selalu tepat dan skalanya konstan sedangkan skala untuk IEEE FP menurun dengan nilai.
1
Apa hubungannya itu dengan uang? Organisasi akuntansi di seluruh dunia biasanya memiliki persyaratan yang sangat spesifik tentang cara Anda melakukan matematika dalam mata uang mereka. Apakah BigDecimal benar-benar cocok dengan setiap standar ini? Akankah itu dilakukan tahun depan, ketika standar itu berubah? Dan BigDecimal bahkan tidak mendekati untuk menentukan aturan pembulatan yang berguna untuk mata uang.
James Moore
2

Anda harus sangat berhati-hati saat berurusan dengan waktu dan uang.

Ketika Anda bekerja dengan uang, saya harap semua orang tahu untuk tidak pernah menggunakan pelampung atau ganda.

Tapi saya tidak yakin tentang BigDecimal.

Dalam kebanyakan kasus, Anda akan baik-baik saja jika Anda hanya melacak sen dalam int atau long. Dengan cara ini Anda tidak pernah berurusan dengan tempat desimal.

Anda hanya menampilkan dolar saat mencetaknya. Selalu bekerja dengan sen internal menggunakan bilangan bulat. Ini mungkin sulit jika perlu membagi atau perlu menggunakan Math.abs ().

Namun, Anda mungkin peduli setengah sen, atau bahkan seperseratus sen. Saya tidak tahu cara apa yang baik untuk melakukan ini. Anda mungkin hanya perlu berurusan dengan seperseribu sen dan menggunakan jangka panjang. Atau mungkin Anda akan terpaksa menggunakan BigDecimal

Saya akan membaca lebih banyak tentang ini, tetapi abaikan semua orang yang mulai berbicara tentang menggunakan pelampung atau ganda untuk mewakili uang. Mereka hanya mencari masalah.

Saya merasa saran saya belum lengkap, jadi mohon lebih dipikirkan. Anda berurusan dengan tipe berbahaya!

Pyrolistik
sumber
2
Mengapa Anda harus "dipaksa" menggunakan BigDecimal? Apa yang Anda tidak yakin? Ini jelas lebih unggul daripada bekerja dengan sen, karena memungkinkan Anda untuk menentukan mode pembulatan secara eksplisit.
Michael Borgwardt
1
@MichaelBorgwardt: ya, ini memungkinkan Anda untuk menentukan subset kecil dari mode pembulatan yang Anda butuhkan untuk mata uang. Begitu? (Petunjuk: pembulatan mata uang diputuskan, biasanya, oleh organisasi akuntansi nasional. Mereka dengan senang hati memasukkan kasus-kasus khusus yang aneh. Lihat stackoverflow.com/questions/5134237/… untuk salah satu dari banyak alasan yang menghibur mengapa pembulatan BigDecimal sepenuhnya tidak berguna di sini.)
James Moore
@ James: Bagaimana tepatnya itu "tidak berguna"? Bagaimana menerapkan kasus khusus ini menjadi lebih sulit dengan BigDecimal dibandingkan dengan yang lain?
Michael Borgwardt
1
Oke, sama sekali tidak berguna terlalu kuat. Dalam kelas rumit yang mengabstraksi mata uang, aturan pembulatan BigDecimal mungkin berguna dalam beberapa contoh tertentu untuk membangun subset dari cara pembulatan mata uang terjadi. Tetapi kasus umumnya adalah bahwa aturan pembulatan untuk mata uang memerlukan mekanisme yang dapat berubah dari waktu ke waktu (karena lembaga akuntansi manusia membuat aturan, dan bebas untuk mengubahnya). Pertanyaannya bukanlah tentang Euro (atau apa pun yang menggantikan Euro bulan depan ...), atau dolar pada tahun 2011, ini tentang mata uang, jadi Anda harus berurusan dengan banyak kerumitan yang tidak menyenangkan.
James Moore
2

Membuat kelas Uang adalah caranya. Menggunakan BigDecimal (atau bahkan int) di bawahnya. Kemudian menggunakan kelas Mata uang untuk mendefinisikan konvensi pembulatan.

Sayangnya tanpa operator overloading Java membuatnya sangat tidak menyenangkan membuat tipe dasar seperti itu.

Kozyarchuk
sumber
2

Ada perpustakaan yang lebih baik, waktu dan uang . IMO, jauh lebih unggul dari pustaka yang disediakan oleh JDK untuk mewakili 2 konsep ini.

Dónal
sumber
3
Jawaban ini telah diposting tiga tahun lalu. Saat ini, proyek waktu dan uang masih dalam tahap pra-alfa menurut tautan tersebut.
James Moore
1
@JamesMoore Panggilan yang bagus. Jawabannya sekarang sudah berumur 7 tahun dan proyek tersebut masih belum stabil.
Navin
1

Jelas bukan BigDecimal. Ada begitu banyak aturan khusus untuk pembulatan dan presentasi yang harus Anda khawatirkan.

Martin Fowler merekomendasikan penerapan kelas Uang khusus untuk mewakili jumlah mata uang, dan itu juga menerapkan aturan untuk konversi mata uang.

lindelof.dll
sumber
6
dan tipe data yang mendasari kelas Uang-nya? BigDecimal.
ninesided
1
Itu tidak benar. Anda dapat menggunakan Integer di kelas uang, itulah yang dilakukan Martin. Saya telah melakukan ini berkali-kali.
egervari
Namun rekomendasinya benar; kalkulasi yang melibatkan uang adalah rawa besar kasus khusus yang berubah seiring waktu. BigDecimal mungkin berguna sebagai bagian kecil dari solusi, tetapi jelas tidak umum.
James Moore
1

Hei, inilah artikel yang sangat menarik di BigDecimal, dan contoh ilustrasi mengapa terkadang digunakan sebagai pengganti ganda. Tutorial BigDecimal .

arg20
sumber
0

Anda dapat menggunakan kelas DecimalFormat saat pada akhirnya menampilkan nilai mata uang. Ini memberikan dukungan pelokalan dan cukup dapat diperluas.


sumber
0

Saya akan merangkum BigDecimal dalam kelas Uang yang juga memiliki mata uang seperti yang disebutkan di atas. Yang penting adalah Anda melakukan tes unit yang ekstrim dan terutama jika bekerja dengan mata uang yang berbeda. Ada baiknya juga jika Anda menambahkan konstruktor konvinien yang menggunakan string atau metode pabrik yang melakukan hal yang sama sehingga Anda dapat menulis pengujian seperti ini:

   assertEquals(Money.create("100.0 USD").add("10 GBP"),Money.create("116 USD"));
Per Arneng
sumber
0

Selalu ada kendala dan hal spesifik yang terlibat. Siapa pun yang tidak memiliki pengalaman yang memadai untuk memahami masalah halus yang diuraikan dalam artikel berikut harus mempertimbangkan kembali secara serius sebelum berurusan dengan data keuangan dunia nyata:

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

BigDecimal bukanlah satu-satunya representasi yang benar atau satu-satunya bagian dari teka-teki. Mengingat kondisi tertentu, menggunakan kelas Uang yang didukung oleh sen yang disimpan sebagai bilangan bulat bisa mencukupi dan akan jauh lebih cepat daripada BigDecimal. Ya, itu menyiratkan penggunaan dolar sebagai mata uang dan jumlah batas, tetapi batasan seperti itu dapat diterima dengan baik untuk banyak kasus penggunaan dan semua mata uang memiliki kasus khusus untuk pembulatan dan sub-denominasi, jadi tidak ada solusi "universal".

Craig
sumber
1
Sepertinya ini adalah komentar di postingan lain, bukan jawaban sebenarnya. Itu juga terlalu pedas. Silakan coba lebih sopan di masa depan.
Slater Victoroff