Javaでの金額の表現[終了]


94

BigDecimalがJavaで金額を表すためのベストプラクティスとして推奨されていることを理解しています。あなたは何を使うのですか?代わりに使用したいより良いライブラリはありますか?


4
見てみましょうJSR 354
yegor256

1
次に、コピーして拡張できるCurrencyクラスを示します。java
Gilbert Le Blanc

また、JSR-354のリファレンス実装を参照github.com/JavaMoney/jsr354-riを
ビート

回答:


81

BigDecimalはるばる。私は一部の人々が自分の作成を聞いたCashMoneyの通貨での現金価値をカプセル化するクラスを、しかし、皮膚の下に、それはまだだBigDecimal、おそらくで、BigDecimal.ROUND_HALF_EVEN丸め。

編集:ドンが彼の回答で言及しいるように、timeandmoneyのようなオープンソースのプロジェクトがあり、開発者がホイールを再発明する必要がないようにしようと試みたことを称賛しますが、使用するプレアルファライブラリに十分な自信がありません実稼働環境で。さらに、内部を掘り下げると、それらも使用するBigDecimalことがわかります


4
+1。通貨を消費するコンテナークラスも追加することにしました。これは、金額をテーブルにレンダリングするときに便利です。
Daniel Hiller、

1
うん、それはかなり一般的なアプローチであり、それは非常に理にかなっています。セントのようなマイナーな通貨単位がないため、日本円を扱う必要がある場合は、独自の丸め規則が必要になるため、これに対する1つの注意点があります。
2008年

3
@ninesidedは、自分でローリングすることが悪い答えである理由を示す良い例です。「ああ、ところで、$ CURRENCY_Xでは機能しません。」これは、他の多くの通貨でも機能しないことを示す良い兆候です。
James Moore

1
@JamesMoore「自分自身をローリングする」ことは悪いアプローチではないことに同意します。選択するアプローチの考えられる制限に注意する必要があるだけなので、その理由を述べます。通貨ごとに異なる丸めルールを実装するのは簡単ですが、システムがUSDまたはEURでのみ処理する必要がある場合は、過剰に設計する必要はありません。

1
BigDecimalが問題である理由の1つとして、stackoverflow.com / questions / 5134237 /…ご覧ください。惑星全体の会計は特別なケースのほんの一部であり、BigDecimalの敷物の下でそれらすべてを一掃しようとしてもうまくいきません。
James Moore



8

以前に遭遇した便利なライブラリーは、Joda-Moneyライブラリーです。その実装の1つは、確かにBigDecimalに基づいています。これは通貨のISO-4217仕様に基づいており、カスタマイズされた通貨リストをサポートできます(CVS経由でロードされます)。

このライブラリには少数のファイルが含まれており、変更が必要な場合にすばやく処理できます。Joda-Moneyは、Apache 2.0ライセンスの下で公開されています。


7

ドルとセントだけを使用している場合は、長い(小数点以下2桁のオフセット)を使用します。詳細が必要な場合は、大きな10進法が適しています。

どちらの方法でも、おそらく正しい形式を使用する.toString()を持つようにクラスを拡張し、他のメソッドが現れる可能性がある場所として配置します(長い場合、乗算と除算は、10進数が未調整)

また、独自のクラスとインターフェースを定義して使用する場合は、実装を自由に置き換えることができます。


2
気を付けてください、たとえそれが数年後にならなければ、たとえ長くても米国の連邦債務をセントで保持するには短すぎるかもしれません...
インゴ2013

3
私は同意します-BigDecimalを使用する必要があります(または多分円でお金を追跡している場合)-それでも、そのためにコンテナークラスを使用することを真剣に検討します。プログラミングの複雑さのほとんどは、コレクションや組み込み型の周りに小さくて単純なクラスを定義していないことが原因だと思います。
ビルK

3

BigDecimal または別の固定小数点表現は、一般的にお金に必要なものです。

浮動小数点(DoubleFloat)の表現と計算は不正確であり、誤った結果をもたらします。


7
厳密に言えば、BigDecimalも不正確です。これは、私たちが日常的に使用している10進数の丸めによく対応しており、丸めモードを指定できます。
マイケルボルグワート

1
@Michael Borgwardt BigDecimalは、明示的なスケールが指定されている点でIEEE FPとは異なります。すべての操作が正確であるとは限りませんが、これにより、一連の操作と動作が常に正確であり、スケールが一定であるのに対し、IEEE FPのスケールは値とともに減少します。

1
それはお金とどう関係しているのですか?世界中の会計組織には、通常、通貨での計算方法について非常に具体的な要件があります。BigDecimalは、これらの標準のすべてに正確に一致しますか?これらの基準が変更された来年には、そうなりますか?また、BigDecimalは、通貨に有効な丸め規則を指定することすらできません。
James Moore、

2

時間とお金を扱うときは注意が必要です。

あなたがお金で働いているとき、私は誰もがフロートやダブルを決して使用しないことを知っているべきだと思います。

しかし、BigDecimalについてはよくわかりません。

ほとんどの場合、intまたはlongでセントを追跡するだけで問題ありません。この方法では、小数点以下を処理することはありません。

ドルは、印刷するときにのみ表示されます。常に整数を使用して内部セントで動作します。分割する必要がある場合、またはMath.abs()を使用する必要がある場合、これは注意が必要です。

ただし、可能であれば、0.5セント、または100分の1セントでも構いません。これを行うにはどうすればよいかわかりません。1000分の1セントを処理してlongを使用する必要があるだけかもしれません。または多分あなたはBigDecimalを使用することを余儀なくされるでしょう

私はこれについてもっと多くの読書をするでしょうが、お金を表すためにフロートまたはダブルを使用することについて話し始めるすべての人を無視してください。彼らはただ問題を求めているだけです。

アドバイスが足りないようですので、もう少し詳しくお書きください。あなたは危険なタイプを扱っています!


2
BigDecimalを使用するために「強制」する必要があるのはなぜですか?何がわからないの?丸めモードを明示的に指定できるので、セントを使用するよりも明らかに優れています。
マイケルボルグワート

1
@MichaelBorgwardt:はい、通貨に必要な丸めモードの小さなサブセットを指定できます。そう?(ヒント:通貨の丸めは、通常、国の会計組織によって決定されます。変な特殊なケースを投げても大丈夫です。BigDecimalの丸めが完全に行われる多くの面白い理由の1つとして、stackoverflow.com / questions / 5134237 /…を参照してください。ここでは役に立たない。)
ジェームズムーア

@ジェームズ:正確に「役に立たない」とは?BigDecimalを使用すると、他の場合よりも特別なケースの実装がどのように難しくなりますか?
Michael Borgwardt

1
わかりました、まったく役に立たないのは強すぎます。通貨を抽象化する複雑なクラスでは、BigDecimalの丸め規則は、通貨の丸めが発生する方法のサブセットを構築する特定のインスタンスでおそらく役立つでしょう。しかし、一般的なケースでは、通貨の丸めルールには、時間の経過とともに変更されるメカニズムが必要です(人間の会計事務所がルールを作成し、自由に変更できるため)。問題はユーロ(または来月のユーロに代わるもの)や2011年のドルではなく、通貨に関するものなので、厄介な複雑さの多くに対処する必要があります。
James Moore、

2

Moneyクラスを作成するのがよいでしょう。下でBigDecimal(またはint)を使用します。次に、Currencyクラスを使用して丸め規則を定義します。

残念ながら、オペレーターのJavaのオーバーロードがないと、そのような基本的な型を作成するのは非常に不愉快になります。


2

より良いライブラリtimeandmoneyがあります。IMO、これらの2つの概念を表すために、JDKが提供するライブラリよりもはるかに優れています。


3
この回答は3年前に投稿されました。今日、timeandmoneyプロジェクトはそのリンクによると、まだプレアルファ版です。
James Moore

1
@JamesMooreグッドコール。答えは現在7年前で、プロジェクトはまだ安定していません。
Navin、2015

1

間違いなくBigDecimalではありません。四捨五入と表示については、非常に多くの特別なルールがあるため、注意が必要です。

Martin Fowlerは、通貨の金額を表すために専用のMoneyクラスの実装を推奨しており、通貨クラスは通貨換算のルールも実装しています。


6
そして彼のMoneyクラスの基になるデータ型は?BigDecimal。
2008年

1
それは真実ではない。整数をマネークラスで使用できます。これはマーティンが行うことです。私はこれを何度も行っています。
egervari 2011

ただし、推奨事項は正しいです。お金を伴う計算は、時間とともに変化する特別なケースの膨大な沼です。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 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.