J’ai la méthode Hibernate qui me renvoie un BigDecimal. J’ai une autre méthode API à laquelle je dois passer ce nombre, mais il accepte Integer comme paramètre. Je ne peux pas modifier les types de retour ou les types de variable des deux méthodes.
Maintenant, comment convertir le BigDecimal en entier et le passer à la seconde méthode?
Y a-t-il un moyen de s’en sortir?
Vous myBigDecimal.intValueExact()
(ou simplement intValue()
) et il intValue()
même une exception si vous perdiez des informations. Cela retourne un int, mais l’autoboxing s’en charge.
Pouvez-vous garantir que le BigDecimal
ne contiendra jamais une valeur supérieure à Integer.MAX_VALUE
?
Si oui, alors voici votre code appelant intValue
:
Integer.valueOf(bdValue.intValue())
TL; DR
Utilisez l’un d’eux 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.
BigDecimal
aura-t-il potentiellement une partie non nulle? BigDecimal
risque-t-il de ne pas entrer dans la plage Integer
? Si vous avez répondu non aux deux 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 2, alors intValue()
est toujours la mauvaise réponse.
Le rendre meilleur
Utilisons les hypothèses suivantes basées sur les autres réponses.
intValueExact()
et la mise en boîte automatique BigDecimal
est plus grand que la plage Integer
, car toute autre chose serait folle à moins que vous ayez un besoin très spécifique de bouclage qui survient lorsque vous déposez les bits de poids fort. Compte tenu de ces parameters, intValueExact()
génère une exception lorsque nous ne le souhaitons pas si notre partie fractionnaire est différente de zéro. Par contre, intValue()
ne lance pas d’exception quand il le faudrait si notre BigDecimal
est trop grand.
Pour obtenir le meilleur des deux mondes, arrondissez d’abord BigDecimal
, puis convertissez. Cela a également l’avantage de vous donner plus de contrôle sur le processus d’arrondissement.
Test 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") Ssortingng decimalAsBigIntSsortingng = decimal.toBigInteger().toSsortingng() Ssortingng hugeDecimalAsBigIntSsortingng = hugeDecimal.toBigInteger().toSsortingng() Ssortingng reallyHugeAsBigIntSsortingng = reallyHuge.toBigInteger().toSsortingng() expect: 'decimals that can be truncated within Integer range to do so without exception' //GOOD: Truncates without exception '' + decimal.intValue() == decimalAsBigIntSsortingng //BAD: Throws ArithmeticException 'Non-zero decimal digits' because we lose information // decimal.intValueExact() == decimalAsBigIntSsortingng //GOOD: Truncates without exception '' + decimal.setScale(0, RoundingMode.DOWN).intValueExact() == decimalAsBigIntSsortingng and: 'truncated decimal that cannot be truncated within Integer range throw conversionOverflow exception' //BAD: hugeDecimal.intValue() is -2147483648 instead of 2147483648 //'' + hugeDecimal.intValue() == hugeDecimalAsBigIntSsortingng //BAD: Throws ArithmeticException 'Non-zero decimal digits' because we lose information //'' + hugeDecimal.intValueExact() == hugeDecimalAsBigIntSsortingng //GOOD: Throws conversionOverflow ArithmeticException because to large //'' + hugeDecimal.setScale(0, RoundingMode.DOWN).intValueExact() == hugeDecimalAsBigIntSsortingng and: 'truncated decimal that cannot be truncated within Integer range throw conversionOverflow exception' //BAD: hugeDecimal.intValue() is 0 //'' + reallyHuge.intValue() == reallyHugeAsBigIntSsortingng //GOOD: Throws conversionOverflow ArithmeticException because to large //'' + reallyHuge.intValueExact() == reallyHugeAsBigIntSsortingng //GOOD: Throws conversionOverflow ArithmeticException because to large //'' + reallyHuge.setScale(0, RoundingMode.DOWN).intValueExact() == reallyHugeAsBigIntSsortingng and: 'if using Java 8, BigInteger has intValueExact() just like BigDecimal' //decimal.toBigInteger().intValueExact() == decimal.setScale(0, RoundingMode.DOWN).intValueExact() }
Eh bien, vous pourriez appeler BigDecimal.intValue()
:
Convertit ce BigDecimal en un int. Cette conversion est analogue à une conversion primitive réduite du double au court tel que défini 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, seule la partie basse -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.
Ce qui suit devrait faire l’affaire:
BigDecimal d = new BigDecimal(10); int i = d.intValue();
Avez-vous essayé d’appeler BigInteger # intValue () ?
Voir BigDecimal # intValue ()
J’ai trouvé que ce qui précède ne fonctionnait pas pour moi. Je tirais une valeur de cellule d’un JTable, mais je ne pouvais pas la 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 aidera quelqu’un qui défile encore!