TL; DR
utilizar uno de estos para la conversión universal debe
//Java 7 or below
bigDecimal.setScale(0, RoundingMode.DOWN).intValueExact()
//Java 8
bigDecimal.toBigInteger().intValueExact()
Razonamiento
La respuesta depende de cuáles son los requisitos y la forma de contestar a estas preguntas.
- ¿Puede el
BigDecimal
tener una parte fraccionaria distinta de cero?
- ¿Puede el
BigDecimal
no encajar en el rango Integer
?
- ¿Desea que las partes fraccionales distintas de cero se redondeen o trunquen?
- ¿Cómo le gustaría que se redondearan partes fraccionales distintas de cero?
Si respondió no a las primeras 2 preguntas, podría simplemente usar BigDecimal.intValueExact()
como otros han sugerido y dejarlo explotar cuando ocurra algo inesperado.
Si no está del todo seguro al 100% sobre la pregunta número 2, entonces intValue()
es siempre la respuesta incorrecta.
Es muchísimo mejor
Vamos a usar las siguientes suposiciones basadas en las otras respuestas.
- estamos bien con la pérdida de precisión y truncar el valor porque eso es lo
intValueExact()
y auto-boxeo hacer
- queremos una excepción lanzada cuando el
BigDecimal
es mayor que el rango Integer
porque cualquier otra cosa sería una locura a menos que tienen una necesidad muy específica de envoltura que sucede cuando sueltas los bits de orden superior.
Dados esos parámetros, intValueExact()
arroja una excepción cuando no lo queremos si nuestra parte fraccionaria no es cero. Por otro lado, intValue()
no arroja una excepción cuando debería si nuestro BigDecimal
es demasiado grande.
Para obtener lo mejor de ambos mundos, redondee primero el BigDecimal
y luego convierta. Esto también tiene el beneficio de darle más control sobre el proceso de redondeo.
Spock maravillosa prueba
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()
}
Corregí tu título. Esta es * conversión, * no * fundición. * – EJP