TL; DR
Użyj jednego z nich do powszechnego nawrócenia potrzebuje
//Java 7 or below
bigDecimal.setScale(0, RoundingMode.DOWN).intValueExact()
//Java 8
bigDecimal.toBigInteger().intValueExact()
rozumowanie
Odpowiedź zależy od tego, jakie są wymagania i jak odpowiedzieć na te pytanie.
- Czy
BigDecimal
może mieć niezerową część ułamkową?
- Czy
BigDecimal
może nie pasować do zakresu Integer
?
- Czy chcesz, aby niezerowe części ułamkowe były zaokrąglone lub skrócone?
- Jak chcesz zaokrąglone niezerowe części ułamkowe?
Jeśli odpowiedziałeś "nie" na pierwsze 2 pytania, możesz po prostu użyć BigDecimal.intValueExact()
, tak jak sugerowali inni, i pozwól mu wysadzić w powietrze, gdy wydarzy się coś nieoczekiwanego.
Jeśli nie jesteś absolutnie w 100% pewny co do pytania numer 2, to intValue()
jest zawsze złą odpowiedzią.
Making to lepiej
Użyjmy następujące założenia oparte na innych odpowiedzi.
- Jesteśmy w porządku z utraty precyzji i obcięcie wartości, ponieważ to właśnie
intValueExact()
i auto-boxing zrobić
- Chcemy wyjątek rzucony kiedy
BigDecimal
jest większy niż zakres Integer
bo cokolwiek innego byłoby szalone chyba że mają bardzo specyficzną potrzebę owijania, która ma miejsce po upuszczeniu bitów wyższego rzędu.
Biorąc pod uwagę te parametry, intValueExact()
zgłasza wyjątek, gdy nie chcemy, aby nasza część ułamkowa była niezerowa. Z drugiej strony, intValue()
nie generuje wyjątku, gdy powinien, jeśli nasz BigDecimal
jest zbyt duży.
Aby uzyskać najlepsze z obu światów, zaokrąglij najpierw BigDecimal
, a następnie przekonwertuj. Ma to także tę zaletę, że daje większą kontrolę nad procesem zaokrąglania.
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()
}
Poprawiłem Twój tytuł. To jest * konwersja, * nie * odlewanie. * – EJP