Konvertieren von BigDecimal in Integer

134

Ich habe eine Hibernate-Methode, die mir ein BigDecimal zurückgibt. Ich habe eine andere API-Methode, an die ich diese Nummer übergeben muss, aber sie akzeptiert Integer als Parameter. Ich kann die Rückgabetypen oder Variablentypen beider Methoden nicht ändern.

Wie konvertiere ich nun BigDecimal in Integer und übergebe es an die zweite Methode?

Gibt es einen Ausweg?

Vishal
quelle
6
Ich habe deinen Titel korrigiert. Dies ist Konvertierung, kein Casting.
Marquis von Lorne

Antworten:

209

Sie würden anrufen myBigDecimal.intValueExact()(oder nur intValue()) und es wird sogar eine Ausnahme auslösen, wenn Sie Informationen verlieren würden. Das gibt ein int zurück, aber Autoboxing kümmert sich darum.

willcodejavaforfood
quelle
1
intValueExact()ist eine gute Empfehlung; es wurde in 1.5
Anon
Anrufen intValue()ist gefährlich, es sei denn, Sie setzen zu 100% darauf, dass die Nummer innerhalb des IntegerBereichs liegt.
Snekse
1
Ist dies sinnvoll: "Integer.valueOf (myBigDecimal.intValueExact ())"?
OddDev
32

Können Sie garantieren, dass der BigDecimalniemals einen Wert größer als enthält?Integer.MAX_VALUE ?

Wenn ja, dann ist hier Ihr Code intValue:

Integer.valueOf(bdValue.intValue())
Anon
quelle
Ja. Ich denke, es wird keinen größeren Wert als Integer.MAX_VALUE enthalten
Vishal
2
Es gibt keinen Grund, den Wert von anders zu machen, als ein Objekt anstelle eines primitiven zu erhalten, oder?
Basil
Ich würde sagen, dies sollte die offizielle Antwort sein, weil a. erwähnt die Grenzen, b. verhindert Autoboxing.
Ledlogic
22

TL; DR

Verwenden Sie eine davon für universelle Konvertierungsanforderungen

//Java 7 or below
bigDecimal.setScale(0, RoundingMode.DOWN).intValueExact()
//Java 8    
bigDecimal.toBigInteger().intValueExact()

Argumentation

Die Antwort hängt davon ab, welche Anforderungen gestellt werden und wie Sie diese Frage beantworten.

  • Wird der BigDecimalpotenziell einen Bruchteil ungleich Null haben?
  • Passt das BigDecimalmöglicherweise nicht in den IntegerBereich?
  • Möchten Sie Bruchteile ungleich Null gerundet oder abgeschnitten?
  • Wie möchten Sie, dass Bruchteile ungleich Null gerundet werden?

Wenn Sie die ersten beiden Fragen mit Nein beantwortet haben, können Sie sie einfach BigDecimal.intValueExact()wie von anderen vorgeschlagen verwenden und in die Luft jagen lassen, wenn etwas Unerwartetes passiert.

Wenn Sie in Bezug auf Frage 2 nicht absolut 100% sicher sind, intValue()ist dies immer die falsche Antwort.

Es besser machen

Verwenden wir die folgenden Annahmen basierend auf den anderen Antworten.

  • Wir sind damit einverstanden, an Präzision zu verlieren und den Wert abzuschneiden, denn genau das intValueExact()tun Auto-Boxing
  • Wir möchten, dass eine Ausnahme ausgelöst wird, wenn der BigDecimalWert größer als der IntegerBereich ist, da alles andere verrückt wäre, es sei denn, Sie haben einen ganz bestimmten Bedarf an dem Umlauf, der auftritt, wenn Sie die höherwertigen Bits ablegen.

Wenn diese Parameter gegeben sind, wird intValueExact()eine Ausnahme ausgelöst, wenn dies nicht gewünscht wird, wenn unser Bruchteil nicht Null ist. Auf der anderen Seite intValue()wirft keine Ausnahme, wenn es sollte, wenn unsere BigDecimalzu groß ist.

Um das Beste aus beiden Welten zu erhalten, runden Sie die BigDecimalerste ab und konvertieren Sie dann. Dies hat auch den Vorteil, dass Sie mehr Kontrolle über den Rundungsprozess haben.

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()
}
Snekse
quelle
18

Nun, Sie könnten anrufen BigDecimal.intValue():

Konvertiert dieses BigDecimal in ein int. Diese Konvertierung ist analog zu einer verengenden primitiven Konvertierung von double nach short, wie in der Java-Sprachspezifikation definiert: Jeder Bruchteil dieses BigDecimal wird verworfen, und wenn die resultierende "BigInteger" zu groß ist, um in ein int zu passen, nur das niedrige -Ordnung 32 Bit werden zurückgegeben. Beachten Sie, dass bei dieser Konvertierung Informationen über die Gesamtgröße und -genauigkeit dieses BigDecimal-Werts verloren gehen und ein Ergebnis mit dem entgegengesetzten Vorzeichen zurückgegeben werden kann.

Sie können dann entweder explizit aufrufen Integer.valueOf(int)oder Auto-Boxing für Sie erledigen lassen, wenn Sie eine ausreichend aktuelle Version von Java verwenden.

Jon Skeet
quelle
9

Folgendes sollte den Trick machen:

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

Ich stellte fest, dass das oben genannte für mich nicht funktionierte. Ich habe einen Zellenwert aus einer JTable gezogen, konnte ihn jedoch nicht in double oder int usw. umwandeln. Meine Lösung:

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

Dabei wäre Zeile 0 immer eine Zahl. Hoffe das hilft jedem noch beim Scrollen!

Bienenstock
quelle