TL; DR
Используйте один из них для универсальных конверсионных нужд
//Java 7 or below
bigDecimal.setScale(0, RoundingMode.DOWN).intValueExact()
//Java 8
bigDecimal.toBigInteger().intValueExact()
Рассуждения
Ответ зависит от требований и от того, как вы ответите на этот вопрос.
- Будет ли
BigDecimal
потенциально иметь ненулевую дробную часть?
- Неужели
BigDecimal
потенциально не вписывается в диапазон Integer
?
- Хотели бы вы, чтобы ненулевые дробные части были округлены или усечены?
- Как бы вы хотели округлить ненулевые дробные части?
Если вы ответили «нет» на первые два вопроса, вы можете просто использовать BigDecimal.intValueExact()
, как предлагали другие, и позволить ему взорваться, когда произойдет что-то неожиданное.
Если вы не уверены на 100% в вопросе № 2, тогда intValue()
- это всегда неправильный ответ.
Делаем лучше
Давайте использовать следующие предположения на основе других ответов.
- Мы в порядке с потерей точности и усечением значения, потому что это то, что
intValueExact()
и автобокс делают
- Мы хотим создать исключение, когда
BigDecimal
больше, чем диапазон Integer
, потому что все остальное было бы сумасшествием, если у вас нет особой необходимости в переборе, которое происходит, когда вы отбрасываете старшие биты.
Учитывая эти параметры, intValueExact()
выдает исключение, когда мы не хотим, чтобы, если наша дробная часть отлична от нуля. С другой стороны, intValue()
не выдает исключение, когда должно быть, если наш BigDecimal
слишком велик.
Чтобы получить лучшее из обоих миров, сначала округлите BigDecimal
, затем конвертируйте. Это также дает вам больше контроля над процессом округления.
Испытание Спока 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()
}