web-dev-qa-db-fra.com

Conversion de BigDecimal en entier

J'ai une méthode Hibernate qui me renvoie un BigDecimal. J'ai une autre méthode API à laquelle j'ai besoin de passer ce nombre, mais elle accepte Integer en tant que paramètre. Je ne peux pas changer les types de retour ou les types de variable des deux méthodes.

Maintenant, comment convertir le BigDecimal en Integer et le transmettre à une seconde méthode?

Y a-t-il un moyen de sortir de cela?

126
Vishal

Vous appelez myBigDecimal.intValueExact() (ou simplement intValue() ) et une exception sera même levée si vous perdez des informations. Cela retourne un int, mais l'autoboxing s'en occupe.

197

Pouvez-vous garantir que BigDecimal ne contiendra jamais une valeur supérieure à Integer.MAX_VALUE ?

Si oui, alors voici votre code appelant intValue :

_Integer.valueOf(bdValue.intValue())
_
32
Anon

TL; DR

Utilisez-en un pour les besoins de conversion universels

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

Raisonnement

La réponse dépend des exigences et de la façon dont vous répondez à cette question.

  • La BigDecimal aura-t-elle potentiellement une partie fractionnaire différente de zéro?
  • La BigDecimal ne rentrera-t-elle pas potentiellement dans la plage Integer?
  • Souhaitez-vous que les fractions non nulles soient arrondies ou tronquées?
  • Comment voudriez-vous que les fractions non nulles soient arrondies?

Si vous avez répondu non aux 2 premières questions, vous pouvez simplement utiliser BigDecimal.intValueExact() comme l'ont suggéré d'autres personnes et le laisser exploser lorsqu'un événement imprévu se produit.

Si vous n'êtes pas absolument sûr à 100% de la question 2, alors intValue() est toujours la mauvaise réponse.

Rendre les choses meilleures

Utilisons les hypothèses suivantes basées sur les autres réponses.

  • Nous sommes d'accord pour perdre de la précision et tronquer la valeur parce que c'est ce que font intValueExact() et la boxe automatique.
  • Nous voulons une exception levée lorsque la variable BigDecimal est supérieure à la plage Integer, car toute autre option serait folle, sauf si vous avez un besoin très spécifique pour le bouclage qui se produit lorsque vous supprimez les bits de poids fort.

Compte tenu de ces paramètres, intValueExact() lève une exception lorsque nous ne le voulons pas si notre partie fractionnaire est non nulle. D'autre part, intValue() ne lève pas d'exception lorsqu'il le devrait si notre BigDecimal est trop volumineux.

Pour obtenir le meilleur des deux mondes, arrondissez d'abord la BigDecimal, puis convertissez-la. Cela présente également l'avantage de vous donner plus de contrôle sur le processus d'arrondi.

Test de 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
Snekse

Eh bien, vous pouvez appeler BigDecimal.intValue() :

Convertit ce BigDecimal en int. Cette conversion est analogue à une conversion primitive restrictive de double à court telle que définie dans la spécification de langage Java: toute partie décimale de ce BigDecimal sera ignorée, et si le "BigInteger" résultant est trop gros pour tenir int, seuls les 32 bits de poids faible sont renvoyés. Notez que cette conversion peut perdre des informations sur la magnitude et la précision globales de cette valeur BigDecimal, ainsi que renvoyer un résultat avec le signe opposé.

Vous pouvez ensuite appeler explicitement Integer.valueOf(int) ou laisser la boxe automatique le faire pour vous si vous utilisez une version suffisamment récente de Java.

17
Jon Skeet

Suivre devrait faire l'affaire:

BigDecimal d = new BigDecimal(10);
int i = d.intValue();
8
Gareth Davis

Avez-vous essayé d'appeler BigInteger # intValue () ?

1
Riduidel
0
Kevin