TL; DR
Використовуйте один із них для універсальних потреб перетворення
//Java 7 or below
bigDecimal.setScale(0, RoundingMode.DOWN).intValueExact()
//Java 8
bigDecimal.toBigInteger().intValueExact()
Обґрунтування
Відповідь залежить від того, які вимоги є і як ви відповісте на це запитання.
- Чи матиме
BigDecimal
потенційно ненульова дробова частина?
- Чи
BigDecimal
потенційно не впишеться в Integer
асортимент?
- Ви хочете, щоб ненульові дробові деталі були округленими або усіченими?
- Як би ви хотіли округлити ненульові дробові частини?
Якщо ви відповіли "ні" на перші 2 запитання, можете просто скористатися BigDecimal.intValueExact()
як запропонували інші, і нехай це підірветься, коли трапиться щось несподіване.
Якщо ви не абсолютно 100% впевнені в питанні №2, то intValue()
це завжди неправильна відповідь.
Зробити це краще
Давайте скористаємось наступними припущеннями на основі інших відповідей.
- Ми все гаразд, втрачаючи точність і максимізуючи значення, тому що ось що
intValueExact()
і робить автоматичний бокс
- Ми хочемо, щоб виняток було викинуто, коли значення
BigDecimal
більше, ніжInteger
діапазон діапазон, тому що будь-що інше було б божевільним, якщо у вас немає дуже специфічної потреби в обгортанні, що відбувається, коли ви скидаєте біти високого порядку.
З огляду на ці парами, intValueExact()
викидає виняток, коли ми цього не хочемо, якщо наша дробова частина не дорівнює нулю. З іншого боку, intValue()
не кидайте винятку, коли це повинно, якщо є нашеBigDecimal
занадто великий.
Щоб отримати найкраще з обох світів, округніть цей BigDecimal
перший, а потім конвертуйте. Це також має перевагу, що надає вам більше контролю над процесом округлення.
Тест Спока Гроуви
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()
}