การแปลง BigDecimal เป็น Integer


136

ฉันมีเมธอด Hibernate ซึ่งคืนค่า BigDecimal ให้ฉัน ฉันมีวิธี API อื่นที่ฉันต้องการส่งผ่านหมายเลขนั้น แต่ยอมรับจำนวนเต็มเป็นพารามิเตอร์ ฉันไม่สามารถเปลี่ยนประเภทผลตอบแทนหรือประเภทตัวแปรของทั้งสองวิธี

ตอนนี้จะแปลง BigDecimal เป็นจำนวนเต็มและส่งต่อไปยังวิธีที่สองได้อย่างไร

มีทางออกจากสิ่งนี้หรือไม่?


6
ฉันแก้ไขชื่อของคุณแล้ว นี่คือการแปลงไม่ใช่การหล่อ
Marquis of Lorne

คำตอบ:


210

คุณจะโทรหาmyBigDecimal.intValueExact()(หรือเฉยๆintValue()) และมันจะทำให้เกิดข้อยกเว้นหากคุณจะสูญเสียข้อมูล ที่ส่งคืน int แต่ autoboxing จะดูแลสิ่งนั้น


1
intValueExact()เป็นคำแนะนำที่ดี เพิ่มใน 1.5
อานนท์

การโทรintValue()เป็นสิ่งที่อันตรายเว้นแต่คุณจะเดิมพันชีวิตของคุณ 100% ในเชิงบวกว่าหมายเลขนั้นอยู่ในIntegerช่วง
Snekse

1
สิ่งนี้สมเหตุสมผลหรือไม่: "Integer.valueOf (myBigDecimal.intValueExact ())"
OddDev

32

คุณสามารถรับประกันได้หรือไม่ว่าBigDecimalจะไม่มีค่ามากกว่าInteger.MAX_VALUE?

ถ้าใช่นี่คือรหัสของคุณโทรintValue:

Integer.valueOf(bdValue.intValue())

ใช่. ฉันเดาว่ามันจะไม่มีค่ามากกว่าจำนวนเต็ม MAX_VALUE
Vishal

2
ไม่มีเหตุผลที่จะทำค่าอื่นนอกจากรับ Object แทนที่จะเป็นแบบดั้งเดิมใช่หรือไม่?
เพรา

ฉันจะบอกว่านี่ควรเป็นคำตอบอย่างเป็นทางการเพราะก. กล่าวถึงขีด จำกัด b. ป้องกันการทำกล่องอัตโนมัติ
ledlogic

22

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()
}

18

คุณสามารถโทรBigDecimal.intValue():

แปลง BigDecimal นี้เป็น int การแปลงนี้คล้ายคลึงกับการแปลงแบบดั้งเดิมที่แคบลงจาก double ไปเป็น short ตามที่กำหนดไว้ในข้อกำหนดของภาษา Java: ส่วนที่เป็นเศษส่วนใด ๆ ของ BigDecimal นี้จะถูกทิ้งและหาก "BigInteger" ที่เป็นผลลัพธ์มีขนาดใหญ่เกินไปที่จะใส่ใน int ให้เหลือเพียงค่าต่ำเท่านั้น -order 32 บิตจะถูกส่งกลับ โปรดทราบว่า Conversion นี้อาจสูญเสียข้อมูลเกี่ยวกับขนาดและความแม่นยำโดยรวมของค่า BigDecimal นี้รวมทั้งส่งคืนผลลัพธ์ที่มีเครื่องหมายตรงข้าม

จากนั้นคุณสามารถเรียกอย่างชัดเจนInteger.valueOf(int)หรือปล่อยให้การชกมวยอัตโนมัติทำเพื่อคุณหากคุณใช้ Java เวอร์ชันล่าสุดเพียงพอ





-4

ฉันพบว่าข้างต้นไม่ได้ผลสำหรับฉัน ฉันกำลังดึงค่าเซลล์จาก JTable แต่ไม่สามารถแคสต์เป็นสองเท่าหรือ int ได้วิธีแก้ปัญหาของฉัน:

Object obj = getTable().getValueAt(row, 0);

โดยที่แถว 0 จะเป็นตัวเลขเสมอ หวังว่านี่จะช่วยให้ทุกคนยังคงเลื่อน!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.