2010-10-28 19 views
102

Mam metodę Hibernacja, która zwraca mi BigDecimal. Mam inną metodę API, do której muszę przekazać ten numer, ale akceptuje Integer jako parametr. Nie mogę zmienić typów zwracanych lub typów zmiennych obu metod.Konwersja BigDecimal do Integer

Teraz jak przekonwertować BigDecimal na Integer i przekazać go do drugiej metody?

Czy istnieje wyjście z tego?

+4

Poprawiłem Twój tytuł. To jest * konwersja, * nie * odlewanie. * – EJP

Odpowiedz

162

Zadzwonisz pod numer myBigDecimal.intValueExact() (lub po prostu intValue()), a nawet rzuci wyjątek, jeśli utracisz informacje. To zwraca int, ale zajmuje się tym autoboxing.

+1

'intValueExact()' jest dobrą rekomendacją; dodano 1.5 – Anon

+0

Wywołanie "intValue()' jest niebezpieczne, chyba że jesteś 100% obstawiając swoje życie na nim, co jest pozytywne, że liczba mieści się w zakresie 'Integer'. – Snekse

+1

Czy ma to sens: "Integer.valueOf (myBigDecimal.intValueExact())"? – OddDev

29

Czy możesz zagwarantować, że BigDecimal nigdy nie będzie zawierać wartości większej niż Integer.MAX_VALUE?

Jeśli tak, to tutaj jest kod nazywając intValue:

Integer.valueOf(bdValue.intValue()) 
+0

Tak. Domyślam się, że nie będzie zawierał większej wartości niż Integer.MAX_VALUE – Vishal

+1

Nie ma powodu, aby wykonać valueOf inne niż uzyskać Object zamiast prymitywnego prawa? – Basil

+0

Powiedziałbym, że to powinna być oficjalna odpowiedź, ponieważ. wspomina o ograniczeniach, b. zapobiega autoboxingowi. – ledlogic

5

obserwuję powinno załatwić sprawę:

BigDecimal d = new BigDecimal(10); 
int i = d.intValue(); 
13

Cóż, można nazwać BigDecimal.intValue():

Konwertuje ten plik BigDecimal na int. Ta konwersja jest analogiczna do zwężającej się konwersji pierwotnej z podwójnej na krótką, jak zdefiniowano w Specyfikacji Języka Java: każda ułamkowa część tego BigDecimal zostanie odrzucona, a jeśli wynikły "BigInteger" jest zbyt duży, aby zmieścić się w int, tylko niski -wyjściowe 32 bity są zwracane. Zwróć uwagę, że konwersja ta może spowodować utratę informacji o całkowitej wielkości i precyzji tej wartości BigDecimal, a także zwrócenie wyniku z przeciwnym znakiem.

Można wówczas jawnie wywołać Integer.valueOf(int) albo niech auto boks to zrobić dla Ciebie, jeśli używasz wystarczająco najnowszą wersję Java.

14

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

Uważam, że powyższe nie działa dla mnie. I ciągnął wartości komórki z JTable ale nie mógł rzucić się podwoić lub int itd. Moje rozwiązanie:

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

gdzie rząd 0 zawsze będzie liczbą. Mam nadzieję, że to pomoże każdemu, kto wciąż przewija!