TL; DR
Use um destes para necessidades de conversão universal
//Java 7 or below
bigDecimal.setScale(0, RoundingMode.DOWN).intValueExact()
//Java 8
bigDecimal.toBigInteger().intValueExact()
Raciocínio
A resposta depende de quais são os requisitos e como você responde a essas perguntas.
- O
BigDecimal
potencial terá uma parte fracionária diferente de zero?
- Os
BigDecimal
potencialmente não se encaixam no Integer
intervalo?
- Deseja que partes fracionárias diferentes de zero sejam arredondadas ou truncadas?
- Como você gostaria que partes fracionárias diferentes de zero fossem arredondadas?
Se você respondeu não às 2 primeiras perguntas, você pode simplesmente usar BigDecimal.intValueExact()
como as outras pessoas sugeriram e deixar explodir quando algo inesperado acontecer.
Se você não está absolutamente 100% confiante sobre a pergunta número 2, sempreintValue()
é a resposta errada.
Tornando-o melhor
Vamos usar as seguintes premissas com base nas outras respostas.
- Não há problema em perder precisão e truncar o valor, porque é isso que o
intValueExact()
boxe automático faz
- Queremos uma exceção lançada quando
BigDecimal
for maior que o Integer
intervalo, porque qualquer outra coisa ficaria louca, a menos que você tenha uma necessidade muito específica de contornar o que acontece quando você solta os bits de alta ordem.
Dados esses parâmetros, intValueExact()
lança uma exceção quando não queremos que nossa parte fracionária seja diferente de zero. Por outro lado, intValue()
não lança uma exceção quando deveria, se a nossa BigDecimal
for muito grande.
Para obter o melhor dos dois mundos, termine o BigDecimal
primeiro e depois converta. Isso também tem o benefício de oferecer a você mais controle sobre o processo de arredondamento.
Spock 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()
}