TL; DR
Gunakan salah satunya untuk kebutuhan konversi universal
//Java 7 or below
bigDecimal.setScale(0, RoundingMode.DOWN).intValueExact()
//Java 8
bigDecimal.toBigInteger().intValueExact()
Pemikiran
Jawabannya tergantung pada apa persyaratannya dan bagaimana Anda menjawab pertanyaan ini.
- Apakah yang
BigDecimal
berpotensi memiliki bagian fraksional yang tidak nol?
- Akankah
BigDecimal
berpotensi tidak masuk dalam Integer
kisaran?
- Apakah Anda ingin bagian fraksional nol atau bulat atau terpotong?
- Bagaimana Anda ingin bagian pecahan yang tidak nol membulat?
Jika Anda menjawab tidak untuk 2 pertanyaan pertama, Anda bisa menggunakan BigDecimal.intValueExact()
apa yang disarankan orang lain dan membiarkannya meledak ketika sesuatu yang tidak terduga terjadi.
Jika Anda tidak benar-benar 100% yakin tentang pertanyaan nomor 2, maka intValue()
adalah selalu jawaban yang salah.
Membuatnya lebih baik
Mari kita gunakan asumsi berikut berdasarkan jawaban lain.
- Kami baik-baik saja dengan kehilangan presisi dan memotong nilai karena itulah yang dilakukan
intValueExact()
dan dilakukan secara otomatis
- Kami ingin pengecualian yang dilemparkan ketika
BigDecimal
lebih besar dari Integer
rentang karena hal lain akan menjadi gila kecuali Anda memiliki kebutuhan yang sangat spesifik untuk membungkus yang terjadi ketika Anda menjatuhkan bit orde tinggi.
Dengan param tersebut, intValueExact()
berikan pengecualian ketika kita tidak menginginkannya jika bagian fraksional kita tidak nol. Di sisi lain, intValue()
jangan melempar pengecualian ketika seharusnya jika kita BigDecimal
terlalu besar.
Untuk mendapatkan yang terbaik dari kedua dunia, akhiri yang BigDecimal
pertama, lalu ubah. Ini juga bermanfaat memberi Anda kontrol lebih besar atas proses pembulatan.
Tes Spock Groovy
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()
}