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
первый, а затем конвертируйте. Это также дает вам больше контроля над процессом округления.
Спок Groovy Test
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()
}