TL; DR
Utilizzare uno di questi per esigenze di conversione universali
//Java 7 or below
bigDecimal.setScale(0, RoundingMode.DOWN).intValueExact()
//Java 8
bigDecimal.toBigInteger().intValueExact()
Ragionamento
La risposta dipende da quali sono i requisiti e da come rispondi a queste domande.
- Potrà
BigDecimal
potenzialmente avere una parte frazionaria diversa da zero?
- Intende la
BigDecimal
non potenzialmente adatta alla Integer
gamma?
- Vorresti arrotondare o troncare parti frazionarie diverse da zero?
- Come desideri arrotondare le parti frazionarie diverse da zero?
Se hai risposto no alle prime 2 domande, potresti semplicemente usare BigDecimal.intValueExact()
come altri hanno suggerito e lasciarlo saltare in aria quando succede qualcosa di inaspettato.
Se non si è assolutamente sicuri al 100% circa la domanda numero 2, poi intValue()
è sempre la risposta sbagliata.
Rendendolo migliore
Usiamo i seguenti presupposti in base alle altre risposte.
- Stiamo bene perdendo precisione e troncando il valore perché è ciò che fanno
intValueExact()
e l'auto-boxing
- Vogliamo un'eccezione generata quando
BigDecimal
è maggiore Integer
dell'intervallo perché qualsiasi altra cosa sarebbe pazza a meno che tu non abbia una necessità molto specifica per l'avvolgimento che accade quando si rilasciano i bit di ordine superiore.
Dati questi parametri, intValueExact()
genera un'eccezione quando non lo vogliamo se la nostra parte frazionaria è diversa da zero. D'altra parte, intValue()
non getta un'eccezione quando dovrebbe se la nostra BigDecimal
è troppo grande.
Per ottenere il meglio da entrambi i mondi, completa il BigDecimal
primo, quindi converti. Ciò ha anche il vantaggio di darti un maggiore controllo sul processo di arrotondamento.
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()
}