Conversion de BigDecimal en nombre entier

135

J'ai la méthode Hibernate qui me renvoie un BigDecimal. J'ai une autre méthode API à laquelle je dois transmettre ce numéro mais elle accepte Integer comme paramètre. Je ne peux pas modifier les types de retour ou les types de variables des deux méthodes.

Maintenant, comment convertir le BigDecimal en Integer et le passer à la deuxième méthode?

Y a-t-il un moyen de s'en sortir?

Vishal
la source
6
J'ai corrigé votre titre. C'est de la conversion, pas du casting.
Marquis de Lorne

Réponses:

209

Vous appelleriez myBigDecimal.intValueExact()(ou simplement intValue()) et cela lèverait même une exception si vous perdiez des informations. Cela renvoie un int, mais l'auto-box s'en charge.

willcodejavaforfood
la source
1
intValueExact()est une bonne recommandation; il a été ajouté dans la 1.5
Anon
Suivre intValue()est dangereux à moins que vous ne pariez à 100% sur votre vie en étant sûr que le numéro est dans la Integerfourchette.
Snekse
1
Cela a-t-il un sens: "Integer.valueOf (myBigDecimal.intValueExact ())"?
OddDev
32

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

Si oui, voici votre code appelant intValue:

Integer.valueOf(bdValue.intValue())
Anon
la source
Oui. Je suppose qu'il ne contiendra pas une valeur plus grande que Integer.MAX_VALUE
Vishal
2
Il n'y a aucune raison de faire le valueOf autrement que pour obtenir un objet au lieu d'un droit primitif?
Basil
Je dirais que cela devrait être la réponse officielle car a. mentionne les limites, b. empêche l'autoboxing.
ledlogic
22

TL; DR

Utilisez l'un de ceux-ci 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 manière dont vous répondez à ces questions.

  • Y aura-t-il BigDecimalpotentiellement une partie fractionnaire non nulle?
  • Le BigDecimalpotentiel ne rentrera- t-il pas dans la Integergamme?
  • Souhaitez-vous des parties fractionnaires non nulles arrondies ou tronquées?
  • Comment souhaitez-vous arrondir les parties fractionnaires non nulles?

Si vous avez répondu non aux 2 premières questions, vous pouvez simplement utiliser BigDecimal.intValueExact()comme d'autres l'ont suggéré et laisser exploser quand quelque chose d'inattendu se produit.

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

Faire mieux

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 l'auto-boxing
  • Nous voulons qu'une exception soit levée lorsque le BigDecimalest plus grand que la Integerplage car tout le reste serait fou à moins que vous n'ayez un besoin très spécifique pour le bouclage qui se produit lorsque vous supprimez les bits de poids fort.

Étant donné 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 quand il le devrait si notre BigDecimalest trop grand.

Pour tirer le meilleur parti des deux mondes, arrondissez le BigDecimalpremier, puis convertissez-vous. Cela a é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()
}
Snekse
la source
18

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

Convertit ce BigDecimal en un entier. Cette conversion est analogue à une conversion primitive rétrécie de double à courte telle que définie dans la spécification du langage Java: toute partie fractionnaire de ce BigDecimal sera ignorée, et si le "BigInteger" résultant est trop grand pour tenir dans un int, seul le faible -ordre 32 bits sont renvoyés. Notez que cette conversion peut perdre des informations sur l'ampleur et la précision globales de cette valeur BigDecimal et renvoyer un résultat avec le signe opposé.

Vous pouvez alors appeler explicitement Integer.valueOf(int)ou laisser l'auto-boxing le faire pour vous si vous utilisez une version suffisamment récente de Java.

Jon Skeet
la source
9

Ce qui suit devrait faire l'affaire:

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

J'ai trouvé que ce qui précède ne fonctionnait pas pour moi. J'étais en train d'extraire une valeur de cellule d'un JTable mais je n'ai pas pu convertir en double ou int, etc. Ma solution:

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

où la ligne 0 serait toujours un nombre. J'espère que cela aide tout le monde à faire défiler encore!

ruche
la source