質問

ロングを使用して通貨用の独自のクラスを作成しようとしていましたが、どうやら使用する必要があるようです BigDecimal その代わり。誰かが私が始めるのを手伝ってくれませんか?一番良い使い方は何でしょうか BigDecimalドル通貨の場合、セントの小数点以下 2 桁以下にするなど。の API BigDecimal 膨大な量なので、どの方法を使用すればよいかわかりません。また、 BigDecimal の方が精度は良いですが、それを通過するとすべてが失われるのではありませんか? double?新しいことをしたら BigDecimal(24.99), を使うのとどう違うのか? double?それとも、を使用するコンストラクターを使用する必要がありますか? String その代わり?

役に立ちましたか?

解決

以下にいくつかのヒントを示します。

  1. 使用 BigDecimal 提供される精度が必要な場合は、計算に使用します (金銭の値は多くの場合これを必要とします)。
  2. 使用 NumberFormat 表示用のクラス。このクラスは、さまざまな通貨での金額のローカリゼーションの問題を処理します。ただし、プリミティブのみを受け取ります。したがって、への変換による精度のわずかな変化を許容できる場合は、 double, 、このクラスを使用できます。
  3. を使用するときは、 NumberFormat クラスの場合は、 scale() のメソッド BigDecimal インスタンスを使用して精度と丸め方法を設定します。

追伸:疑問に思われた方のために、 BigDecimal 常により優れています double, 、Java でお金の値を表現する必要がある場合.

PPS:

作成 BigDecimal インスタンス

これは非常に簡単なので、 BigDecimal プリミティブ値を取り込むためのコンストラクターを提供します, 、 そして String オブジェクト。それらを使えばいいのですが、 できれば、 String 物体. 。例えば、

BigDecimal modelVal = new BigDecimal("24.455");
BigDecimal displayVal = modelVal.setScale(2, RoundingMode.HALF_EVEN);

表示する BigDecimal インスタンス

を使用できます setMinimumFractionDigits そして setMaximumFractionDigits メソッドを呼び出して、表示されるデータ量を制限します。

NumberFormat usdCostFormat = NumberFormat.getCurrencyInstance(Locale.US);
usdCostFormat.setMinimumFractionDigits( 1 );
usdCostFormat.setMaximumFractionDigits( 2 );
System.out.println( usdCostFormat.format(displayVal.doubleValue()) );

他のヒント

私はお金のパターンに少し研究をお勧めします。 Martin Fowler氏は、彼の著書の分析パターンでより詳細にこれをカバーしています。

public class Money {

    private static final Currency USD = Currency.getInstance("USD");
    private static final RoundingMode DEFAULT_ROUNDING = RoundingMode.HALF_EVEN;

    private final BigDecimal amount;
    private final Currency currency;   

    public static Money dollars(BigDecimal amount) {
        return new Money(amount, USD);
    }

    Money(BigDecimal amount, Currency currency) {
        this(amount, currency, DEFAULT_ROUNDING);
    }

    Money(BigDecimal amount, Currency currency, RoundingMode rounding) {
        this.currency = currency;      
        this.amount = amount.setScale(currency.getDefaultFractionDigits(), rounding);
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public Currency getCurrency() {
        return currency;
    }

    @Override
    public String toString() {
        return getCurrency().getSymbol() + " " + getAmount();
    }

    public String toString(Locale locale) {
        return getCurrency().getSymbol(locale) + " " + getAmount();
    }   
}

用法に来ます:

Moneyとは対照的に、

あなたはBigDecimalオブジェクトを使用して、すべての金銭を表します。大きな小数としてお金を表現することは、あなたがそれを表示する場所ごとにお金をフォーマットする必要がありますことを意味します。ディスプレイ規格が変更された場合だけで想像してみてください。あなたはすべての場所で編集を行う必要があります。代わりに、あなたは、単一の場所にお金の書式設定を集中Moneyパターンを使用します。

Money price = Money.dollars(38.28);
System.out.println(price);

あるいは、 JSR-354 のを待ちます。 Javaのマネーと通貨APIはもうすぐ!

1)あなたはdouble精度に限定されている場合は、BigDecimalsを使用する1つの理由は、BigDecimalsから作成doublesとの動作を実現することです。

ダブルオブジェクト内のプリミティブ型BigDecimalの値をラップしながら、

2)doubleは、任意精度の整数スケールなしの値と非負32ビット整数スケールで構成されています。型Doubleのオブジェクトは、そのタイプdoubleれる単一のフィールドが含まれて

3)それは作るべき違いはありません。

あなたは$と精度で支障があってはいけません。それを行うための1つの方法は、

System.out.printfを使用しています
あなたがセントで2つの小数点以下第三位を切り上げしたいとき

BigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP)を使用してください。あなたがが計算を行う際に、エラーを丸めるのに注意してください。あなたはお金の価値の丸めを行うことになる際に一貫している必要があります。どちらのは一度だけ、すべての計算が行われた後、最後に丸め権利を行う、または任意の計算を行う前に、各値に丸め適用されます。どちらを使用するためには、ビジネス要件に依存するが、一般的に、私は最後に丸め、右をやって考える私にはより良い感覚を作るようです。

あなたはお金の価値のためにStringを構築する際BigDecimalを使用してください。あなたがdoubleを使用する場合は、末尾に浮動小数点値を持つことになります。これはdouble / float値はバイナリ形式で表現される方法に関するコンピュータ・アーキテクチャに起因するものである。

プリミティブ数値型は、メモリ内の単一の値を格納するために有用です。メモリ表現が値に正確にマップされませんので、しかし、ダブル、フロートタイプを使用して計算を扱うとき、rounding.Itに問題があると起こります。例えば、二重の値は、64ビットを取ることになっているが、Javaは、それは数の重要な部分をどう思うか、すべて64 bits.It店舗のみを使用していません。だから、あなたがfloatまたはdouble型の一緒に値を追加するとき、間違った値に到着することができます。

短いクリップをご覧ください。 https://youtu.be/EXxUSz9x7BMする

javapractices.comにこれを行う方法の豊富な例があります。特に金銭計算を行うことを意図している Money のクラスを、参照してください。直接BigDecimalを使用してよりも簡単。

このMoneyクラスのデザインは、表現がより自然にすることを目的としています。たとえばます:

if ( amount.lt(hundred) ) {
 cost = amount.times(price); 
}

WEB4Jツールは Decimal <呼ばれ、同様のクラスを持っています/ A>、Moneyクラスよりも少し研磨されます。

NumberFormat.getNumberInstance(java.util.Locale.US).format(num);

私なら過激になるでしょう。BigDecimal はありません。

ここに素晴らしい記事がありますhttps://lemnik.wordpress.com/2011/03/25/bigDecimal-and-your-money/

ここからのアイデア。

import java.math.BigDecimal;

public class Main {

    public static void main(String[] args) {
        testConstructors();
        testEqualsAndCompare();
        testArithmetic();
    }

    private static void testEqualsAndCompare() {
        final BigDecimal zero = new BigDecimal("0.0");
        final BigDecimal zerozero = new BigDecimal("0.00");

        boolean zerosAreEqual = zero.equals(zerozero);
        boolean zerosAreEqual2 = zerozero.equals(zero);

        System.out.println("zerosAreEqual: " + zerosAreEqual + " " + zerosAreEqual2);

        int zerosCompare = zero.compareTo(zerozero);
        int zerosCompare2 = zerozero.compareTo(zero);
        System.out.println("zerosCompare: " + zerosCompare + " " + zerosCompare2);
    }

    private static void testArithmetic() {
        try {
            BigDecimal value = new BigDecimal(1);
            value = value.divide(new BigDecimal(3));
            System.out.println(value);
        } catch (ArithmeticException e) {
            System.out.println("Failed to devide. " + e.getMessage());
        }
    }

    private static void testConstructors() {
        double doubleValue = 35.7;
        BigDecimal fromDouble = new BigDecimal(doubleValue);
        BigDecimal fromString = new BigDecimal("35.7");

        boolean decimalsEqual = fromDouble.equals(fromString);
        boolean decimalsEqual2 = fromString.equals(fromDouble);

        System.out.println("From double: " + fromDouble);
        System.out.println("decimalsEqual: " + decimalsEqual + " " + decimalsEqual2);
    }
}

印刷します

From double: 35.7000000000000028421709430404007434844970703125
decimalsEqual: false false
zerosAreEqual: false false
zerosCompare: 0 0
Failed to devide. Non-terminating decimal expansion; no exact representable decimal result.

BigDecimal をデータベースに保存してみてはどうでしょうか?なんと、二重の値としても保存されます。少なくとも、高度な構成を行わずに mongoDb を使用すると、 BigDecimal.TEN として 1E1.

可能な解決策?

私は 1 つを提供しました - String を使用して BigDecimal を Java に保存します データベースに。たとえば、検証があります @NotNull, @Min(10), 、など...その後、更新または保存時にトリガーを使用して、現在の文字列が必要な数値であるかどうかを確認できます。ただし、mongo にはトリガーはありません。Mongodb トリガー関数呼び出しの組み込み方法はありますか?

私が楽しんでいる欠点が 1 つあります - Swagger 定義の文字列としての BigDecimal

フロントエンド チームが String として提示された数値を渡すことを理解できるように、Swagger を生成する必要があります。 日付時刻 たとえば、文字列として表現されます。

上記の記事で読んだ別の素晴らしい解決策があります...使用 長さ 正確な数値を保存します。

標準の Long 値では、オーバーフローすることなく、米国国債の現在価値 (ドルではなくセントとして) を 6,477 回保存できます。そのうえ:浮動小数点ではなく整数型です。これにより、操作が簡単かつ正確になり、動作が保証されます。


アップデート

https://stackoverflow.com/a/27978223/4587961

おそらく将来、MongoDb は BigDecimal のサポートを追加するでしょう。https://jira.mongodb.org/browse/SERVER-13933.3.8 ではこれが行われているようです。

2番目のアプローチの例です。スケーリングを使用します。http://www.technology-ebay.de/the-teams/mobile-de/blog/mapping-bigDecimals-with-morphia-for-mongodb.html

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top