BigDecimalを返すHibernateメソッドがあります。その番号を渡す必要がある別のAPIメソッドがありますが、パラメーターとして整数を受け入れます。両方のメソッドの戻り値の型または変数の型を変更することはできません。
BigDecimalをIntegerに変換して2番目のメソッドに渡す方法は?
これから抜け出す方法はありますか?
myBigDecimal.intValueExact()
(または単に intValue()
)を呼び出すと、情報を失うと例外がスローされます。これはintを返しますが、オートボクシングがそれを処理します。
BigDecimal
に Integer.MAX_VALUE
より大きい値が含まれないことを保証できますか?
はいの場合、 intValue
を呼び出すコードは次のとおりです。
Integer.valueOf(bdValue.intValue())
TL; DR
これらのいずれかをユニバーサル変換のニーズに使用します
//Java 7 or below
bigDecimal.setScale(0, RoundingMode.DOWN).intValueExact()
//Java 8
bigDecimal.toBigInteger().intValueExact()
推論
答えは、要件が何であり、これらの質問にどのように答えるかによって異なります。
BigDecimal
には非ゼロの小数部が含まれる可能性がありますか?BigDecimal
はInteger
の範囲に収まらない可能性がありますか?最初の2つの質問に「いいえ」と答えた場合は、他の人が提案したようにBigDecimal.intValueExact()
を使用し、予期しないことが起こったときに爆発させることができます。
質問番号2について完全に100%自信がない場合、intValue()
はalways間違った答えです。
改善する
他の回答に基づいて、次の仮定を使用してみましょう。
intValueExact()
とオートボクシングが行うことだからです。BigDecimal
がInteger
の範囲よりも大きい場合、例外をスローする必要があります。これは、上位ビットをドロップするときに発生するラップアラウンドの非常に具体的な必要性がない限り、他の何かは狂気になるからです。これらのパラメーターを指定すると、小数部分がゼロ以外の場合、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()
}
まあ、あなたは呼び出すことができます BigDecimal.intValue()
:
このBigDecimalをintに変換します。この変換は、Java言語仕様で定義されているdoubleからshortへの縮小プリミティブ変換に類似しています。このBigDecimalの小数部は破棄され、結果の「BigInteger」が大きすぎてintに収まらない場合は、低-order 32ビットが返されます。この変換では、このBigDecimal値の全体的な大きさと精度に関する情報が失われる可能性があり、逆符号の結果が返される可能性があることに注意してください。
その後、明示的にInteger.valueOf(int)
を呼び出すか、十分に最近のバージョンのJavaを使用している場合は、自動ボクシングを使用することができます。
次のトリックを実行する必要があります。
BigDecimal d = new BigDecimal(10);
int i = d.intValue();
BigInteger#intValue() を呼び出してみましたか?
BigDecimal#intValue() を参照してください