TL; DR
ใช้อย่างใดอย่างหนึ่งสำหรับความต้องการการแปลงสากล
//Java 7 or below
bigDecimal.setScale(0, RoundingMode.DOWN).intValueExact()
//Java 8
bigDecimal.toBigInteger().intValueExact()
เหตุผล
คำตอบขึ้นอยู่กับข้อกำหนดคืออะไรและคุณตอบคำถามเหล่านี้อย่างไร
- การจะ
BigDecimal
อาจมีความไม่เป็นศูนย์ส่วนที่เป็นเศษส่วน?
- การจะ
BigDecimal
อาจไม่พอดีกับInteger
ช่วง?
- คุณต้องการให้ส่วนที่เป็นเศษส่วนที่ไม่ใช่ศูนย์ปัดเศษหรือตัดทอน?
- คุณต้องการให้ส่วนที่เป็นเศษส่วนที่ไม่ใช่ศูนย์ปัดเศษอย่างไร
หากคุณตอบว่าไม่สำหรับ 2 คำถามแรกคุณสามารถใช้BigDecimal.intValueExact()
ตามที่คนอื่นแนะนำและปล่อยให้มันระเบิดเมื่อมีสิ่งที่ไม่คาดคิดเกิดขึ้น
ถ้าคุณไม่ได้อย่างแน่นอน 100% มีความมั่นใจเกี่ยวกับจำนวน 2 คำถามแล้วintValue()
เป็นเสมอคำตอบที่ผิด
ทำให้ดีขึ้น
ลองใช้สมมติฐานต่อไปนี้ตามคำตอบอื่น ๆ
- เราโอเคกับการสูญเสียความแม่นยำและการตัดทอนมูลค่าเพราะนั่นคือสิ่งที่ทำ
intValueExact()
โดยอัตโนมัติ
- เราต้องการให้มีการยกเว้นเมื่อ
BigDecimal
มีขนาดใหญ่กว่าInteger
ช่วงเนื่องจากสิ่งอื่นจะบ้าเว้นแต่คุณจะมีความต้องการเฉพาะเจาะจงมากสำหรับการตัดรอบที่เกิดขึ้นเมื่อคุณวางบิตลำดับสูง
เมื่อพิจารณาพารามิเตอร์เหล่านี้จะintValueExact()
แสดงข้อยกเว้นเมื่อเราไม่ต้องการให้ถ้าส่วนเศษส่วนของเราไม่เป็นศูนย์ ในทางกลับกันintValue()
อย่าทิ้งข้อยกเว้นเมื่อควรถ้าของเราBigDecimal
มีขนาดใหญ่เกินไป
เพื่อให้ได้สิ่งที่ดีที่สุดจากทั้งสองโลกให้ปัดเศษBigDecimal
ก่อนจากนั้นเปลี่ยนใจเลื่อมใส นอกจากนี้ยังมีประโยชน์ในการให้คุณควบคุมกระบวนการปัดเศษได้มากขึ้น
การทดสอบ 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()
}