web-dev-qa-db-ja.com

BigDecimalから整数への変換

BigDecimalを返すHibernateメソッドがあります。その番号を渡す必要がある別のAPIメソッドがありますが、パラメーターとして整数を受け入れます。両方のメソッドの戻り値の型または変数の型を変更することはできません。

BigDecimalをIntegerに変換して2番目のメソッドに渡す方法は?

これから抜け出す方法はありますか?

124
Vishal

myBigDecimal.intValueExact() (または単に intValue() )を呼び出すと、情報を失うと例外がスローされます。これはintを返しますが、オートボクシングがそれを処理します。

195

BigDecimalInteger.MAX_VALUE より大きい値が含まれないことを保証できますか?

はいの場合、 intValue を呼び出すコードは次のとおりです。

Integer.valueOf(bdValue.intValue())
32
Anon

TL; DR

これらのいずれかをユニバーサル変換のニーズに使用します

//Java 7 or below
bigDecimal.setScale(0, RoundingMode.DOWN).intValueExact()
//Java 8    
bigDecimal.toBigInteger().intValueExact()

推論

答えは、要件が何であり、これらの質問にどのように答えるかによって異なります。

  • BigDecimalには非ゼロの小数部が含まれる可能性がありますか?
  • BigDecimalIntegerの範囲に収まらない可能性がありますか?
  • ゼロ以外の小数部分を丸めたり切り捨てたりしますか?
  • ゼロ以外の小数部分をどのように丸めますか?

最初の2つの質問に「いいえ」と答えた場合は、他の人が提案したようにBigDecimal.intValueExact()を使用し、予期しないことが起こったときに爆発させることができます。

質問番号2について完全に100%自信がない場合、intValue()always間違った答えです。

改善する

他の回答に基づいて、次の仮定を使用してみましょう。

  • 精度を失い、値を切り捨てても大丈夫です。なぜなら、それがintValueExact()とオートボクシングが行うことだからです。
  • BigDecimalIntegerの範囲よりも大きい場合、例外をスローする必要があります。これは、上位ビットをドロップするときに発生するラップアラウンドの非常に具体的な必要性がない限り、他の何かは狂気になるからです。

これらのパラメーターを指定すると、小数部分がゼロ以外の場合、intValueExact()は、必要ないときに例外をスローします。一方、BigDecimalが大きすぎる場合、intValue()は例外をスローしません。

両方の世界を最大限に活用するには、最初にBigDecimalを四捨五入してから変換します。これには、丸めプロセスをより詳細に制御できるという利点もあります。

Spock Groovyテスト

void 'test BigDecimal rounding'() {
    given:
    BigDecimal decimal = new BigDecimal(Integer.MAX_VALUE - 1.99)
    BigDecimal hugeDecimal = new BigDecimal(Integer.MAX_VALUE + 1.99)
    BigDecimal reallyHuge = new BigDecimal("10000000000000000000000000000000000000000000000")
    String decimalAsBigIntString = decimal.toBigInteger().toString()
    String hugeDecimalAsBigIntString = hugeDecimal.toBigInteger().toString()
    String reallyHugeAsBigIntString = reallyHuge.toBigInteger().toString()

    expect: 'decimals that can be truncated within Integer range to do so without exception'
    //GOOD: Truncates without exception
    '' + decimal.intValue() == decimalAsBigIntString
    //BAD: Throws ArithmeticException 'Non-zero decimal digits' because we lose information
    // decimal.intValueExact() == decimalAsBigIntString
    //GOOD: Truncates without exception
    '' + decimal.setScale(0, RoundingMode.DOWN).intValueExact() == decimalAsBigIntString

    and: 'truncated decimal that cannot be truncated within Integer range throw conversionOverflow exception'
    //BAD: hugeDecimal.intValue() is -2147483648 instead of 2147483648
    //'' + hugeDecimal.intValue() == hugeDecimalAsBigIntString
    //BAD: Throws ArithmeticException 'Non-zero decimal digits' because we lose information
    //'' + hugeDecimal.intValueExact() == hugeDecimalAsBigIntString
    //GOOD: Throws conversionOverflow ArithmeticException because to large
    //'' + hugeDecimal.setScale(0, RoundingMode.DOWN).intValueExact() == hugeDecimalAsBigIntString

    and: 'truncated decimal that cannot be truncated within Integer range throw conversionOverflow exception'
    //BAD: hugeDecimal.intValue() is 0
    //'' + reallyHuge.intValue() == reallyHugeAsBigIntString
    //GOOD: Throws conversionOverflow ArithmeticException because to large
    //'' + reallyHuge.intValueExact() == reallyHugeAsBigIntString
    //GOOD: Throws conversionOverflow ArithmeticException because to large
    //'' + reallyHuge.setScale(0, RoundingMode.DOWN).intValueExact() == reallyHugeAsBigIntString

    and: 'if using Java 8, BigInteger has intValueExact() just like BigDecimal'
    //decimal.toBigInteger().intValueExact() == decimal.setScale(0, RoundingMode.DOWN).intValueExact()
}
18
Snekse

まあ、あなたは呼び出すことができます BigDecimal.intValue()

このBigDecimalをintに変換します。この変換は、Java言語仕様で定義されているdoubleからshortへの縮小プリミティブ変換に類似しています。このBigDecimalの小数部は破棄され、結果の「BigInteger」が大きすぎてintに収まらない場合は、低-order 32ビットが返されます。この変換では、このBigDecimal値の全体的な大きさと精度に関する情報が失われる可能性があり、逆符号の結果が返される可能性があることに注意してください。

その後、明示的にInteger.valueOf(int)を呼び出すか、十分に最近のバージョンのJavaを使用している場合は、自動ボクシングを使用することができます。

17
Jon Skeet

次のトリックを実行する必要があります。

BigDecimal d = new BigDecimal(10);
int i = d.intValue();
8
Gareth Davis

BigInteger#intValue() を呼び出してみましたか?

1
Riduidel

BigDecimal#intValue() を参照してください

0
Kevin