Mengubah BigDecimal ke Integer

134

Saya memiliki metode Hibernate yang mengembalikan saya BigDecimal. Saya memiliki metode API lain yang harus saya lewati angka itu tetapi menerima Integer sebagai parameter. Saya tidak bisa mengubah tipe pengembalian atau tipe variabel dari kedua metode.

Sekarang bagaimana cara mengubah BigDecimal menjadi Integer dan meneruskannya ke metode kedua?

Apakah ada jalan keluar dari ini?

Vishal
sumber
6
Saya mengoreksi judul Anda. Ini adalah konversi, bukan casting.
Marquis of Lorne

Jawaban:

209

Anda akan menelepon myBigDecimal.intValueExact()(atau hanya intValue()) dan bahkan akan mengeluarkan pengecualian jika Anda akan kehilangan informasi. Yang mengembalikan int tetapi autoboxing mengurusnya.

willcodejavaforfood
sumber
1
intValueExact()adalah rekomendasi yang bagus; itu ditambahkan dalam 1,5
Anon
Menelepon intValue()itu berbahaya kecuali jika Anda 100% mempertaruhkan hidup Anda untuk itu positif bahwa angkanya ada dalam Integerkisaran.
Snekse
1
Apakah ini masuk akal: "Integer.valueOf (myBigDecimal.intValueExact ())"?
OddDev
32

Bisakah Anda menjamin bahwa BigDecimaltidak akan pernah mengandung nilai lebih besar dari Integer.MAX_VALUE?

Jika ya, maka ini panggilan kode Anda intValue:

Integer.valueOf(bdValue.intValue())
Segera
sumber
Iya. Saya kira itu tidak akan mengandung nilai yang lebih besar dari Integer.MAX_VALUE
Vishal
2
Tidak ada alasan untuk melakukan valueOf selain untuk mendapatkan Object, bukan primitif, kan?
Basil
Saya akan mengatakan ini harus menjadi jawaban resmi karena a. menyebutkan batasannya, b. mencegah autoboxing.
ledlogic
22

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 BigDecimalberpotensi memiliki bagian fraksional yang tidak nol?
  • Akankah BigDecimalberpotensi tidak masuk dalam Integerkisaran?
  • 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 BigDecimallebih besar dari Integerrentang 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 BigDecimalterlalu besar.

Untuk mendapatkan yang terbaik dari kedua dunia, akhiri yang BigDecimalpertama, 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()
}
Snekse
sumber
18

Nah, Anda bisa menelepon BigDecimal.intValue():

Mengubah BigDecimal ini menjadi int. Konversi ini dianalogikan dengan konversi primitif yang menyempit dari ganda ke pendek seperti yang didefinisikan dalam Spesifikasi Bahasa Jawa: setiap bagian pecahan dari BigDecimal ini akan dibuang, dan jika "BigInteger" yang dihasilkan terlalu besar untuk dapat dimasukkan ke dalam int, hanya yang rendah -memesan 32 bit dikembalikan. Perhatikan bahwa konversi ini dapat kehilangan informasi tentang keseluruhan dan presisi nilai BigDecimal ini serta mengembalikan hasil dengan tanda yang berlawanan.

Anda kemudian dapat secara eksplisit memanggil Integer.valueOf(int)atau membiarkan tinju otomatis melakukannya untuk Anda jika Anda menggunakan versi Java yang cukup baru.

Jon Skeet
sumber
9

Mengikuti harus melakukan trik:

BigDecimal d = new BigDecimal(10);
int i = d.intValue();
Gareth Davis
sumber
-4

Saya menemukan bahwa di atas tidak bekerja untuk saya. Saya menarik nilai sel dari JTable tetapi tidak bisa melakukan double atau int dll. Solusi saya:

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

di mana baris 0 akan selalu berupa angka. Semoga ini bisa membantu siapa pun yang masih bergulir!

sarang lebah
sumber