[Java] Utilisez correctement Big Decimal ~ 2018 ~

Dans Java 9, le système BigDecimal # ROUND_ ~ est finalement devenu @ Deprecated. Néanmoins, dans les blogs et les entrées qui expliquent BigDecimal, en expliquant BigDecimal # setScale, BigDecimal # divide, etc., il est expliqué en utilisant le systèmeBigDecimal # ROUND_ ~. Que voulez-vous dire? Tout est «@ obsolète» dans Java 9, n'est-ce pas? J'ai décidé d'écrire un article parce que je me sens mal à l'aise récemment.

Tout d'abord, des bases.

Méthode de génération / usine

De base

Il est essentiellement généré par la méthode suivante.

BigDecimal value = BigDecimal.valueOf(1234.567);//Génération à partir d'un système numérique
BigDecimal value = new BigDecimal("1234.567");//Généré à partir d'une chaîne

Puisque «0», «1», «10» sont déjà définis, utilisez-les.

BigDecimal.ZERO
BigDecimal.ONE
BigDecimal.TEN

Remarques sur la génération à partir de chaînes

La génération à partir de la chaîne de caractères est telle que spécifiée par la chaîne de caractères dans scale.

System.out.println(new BigDecimal("1234.567").scale());  // → 3
System.out.println(new BigDecimal("1234.56700").scale());// → 5

Motif NG généré à partir de valeurs numériques

Utilisez BigDecimal # valueOf pour générer à partir d'un nombre (double). Il serait ridicule de le générer avec «new».

BigDecimal value = new BigDecimal(1234.567);// NG!!Génération à partir d'un système numérique
System.out.println(value);// → 1234.5670000000000072759576141834259033203125

ResultSet#getBigDecimal Lors de l'obtention de ResultSet, il y a ResultSet # getBigDecimal, alors utilisez ceci.

BigDecimal value = rs.getBigDecimal("COL");

Ce qui suit est inutile, donc NG

BigDecimal value = BigDecimal.valueOf(rs.getDouble("COL"));
BigDecimal value = new BigDecimal(rs.getString("COL"));

Quatre règles

Ajouter

BigDecimal a = BigDecimal.valueOf(123);
BigDecimal b = BigDecimal.valueOf(456);

// value = a + b
BigDecimal value = a.add(b);

System.out.println(value);// 579

Soustraire

BigDecimal a = BigDecimal.valueOf(123);
BigDecimal b = BigDecimal.valueOf(456);

// value = a - b
BigDecimal value = a.subtract(b);

System.out.println(value);// -333

Multiplier

BigDecimal a = BigDecimal.valueOf(123);
BigDecimal b = BigDecimal.valueOf(456);

// value = a * b
BigDecimal value = a.multiply(b);

System.out.println(value);// 56088

10 fois, 100 fois, etc.

Utilisez BigDecimal # scaleByPowerOfTen.

BigDecimal src = BigDecimal.valueOf(0.123);
BigDecimal value = src.scaleByPowerOfTen(2);//Centuple(10 au carré)
System.out.println(value);// 12.3

C'est beaucoup plus propre que src.multiply (BigDecimal.valueOf (100)), et vous n'avez pas besoin de créer une instance de 100.

Négatif (inversion de signe)

Utilisez BigDecimal # negate.

BigDecimal src = BigDecimal.valueOf(123);
BigDecimal value = src.negate();
System.out.println(value);// -123

Veuillez arrêter d'écrire ce qui suit.

BigDecimal value = src.multiply(BigDecimal.valueOf(-1));

division

import java.math.RoundingMode;
//・ ・ ・

BigDecimal a = BigDecimal.valueOf(123);
BigDecimal b = BigDecimal.valueOf(456);

// value = a / b
BigDecimal value = a.divide(b, 3 /* ← scale */, RoundingMode.HALF_UP /*← Arrondi*/);

System.out.println(value);// 0.270

Les méthodes qui peuvent être remplacées par RoundingMode ne sont pas disponibles

Le style d'écriture suivant est NG

BigDecimal value = a.divide(b, 3, BigDecimal.ROUND_HALF_UP);

Pour plus d'informations sur le Mode arrondi, veuillez consulter [en bas](# mode arrondi) pour plus de détails.

Spécifiez échelle

Il existe également une méthode BigDecimal # divide qui ne spécifie pas scale, Lorsqu'elle n'est pas divisible, ʻArithmeticException se produira, il est donc préférable d'utiliser la version spécifiée scale`.

1/10, 1/100, etc.

Utilisez BigDecimal # scaleByPowerOfTen.

BigDecimal src = BigDecimal.valueOf(8);
BigDecimal value = src.scaleByPowerOfTen(-2);// 1/100(dix-Au carré)
System.out.println(value);// 0.08

Arrondir / Arrondir / Arrondir

import java.math.RoundingMode;
//・ ・ ・


BigDecimal src = BigDecimal.valueOf(123.456);

//Arrondi
BigDecimal value = src.setScale(2, RoundingMode.HALF_UP);
System.out.println(value); // → 123.46

//Rassembler
BigDecimal value = src.setScale(2, RoundingMode.UP);

//Tronquer
BigDecimal value = src.setScale(2, RoundingMode.DOWN);

Les méthodes qui peuvent être remplacées par RoundingMode ne sont pas disponibles

Le style d'écriture suivant est NG

BigDecimal value = src.setScale(2, BigDecimal.ROUND_HALF_UP);

Pour plus d'informations sur le Mode arrondi, veuillez consulter [en bas](# mode arrondi) pour plus de détails.

Stringification

BigDecimal#toPlainString BigDecimal # toString peut être exponentiel, donc je pense qu'il est préférable d'utiliser BigDecimal # toPlainString.

BigDecimal value = new BigDecimal("0.0000001");
System.out.println(value.toString());     // → 1E-7
System.out.println(value.toPlainString());// → 0.0000001

jackson a également une option pour utiliser toPlainString. JsonGenerator.Feature.html#WRITE_BIGDECIMAL_AS_PLAIN

Supprimer «0» à la fin de la fraction

Les deux «BigDecimal # toString» et «BigDecimal # toPlainString» considèrent «scale» dans la chaîne et sont conservés même si la fraction est suivie de «0». Si vous souhaitez désactiver cette option, utilisez BigDecimal # stripTrailingZeros. Vous n'avez pas à travailler dur avec les expressions régulières.

BigDecimal value = new BigDecimal("1.000000");
		
System.out.println(value);                     // → 1.000000
System.out.println(value.stripTrailingZeros());// → 1

ʻIntlong double`

BigDecimal value = BigDecimal.valueOf(12345);
int i = value.intValue();
long l = value.longValue();
double d = value.doubleValue();

Il y a aussi «float» et «BigInteger».

Version de contrôle de tolérance

Il existe une version de conversion en nombres entiers qui lève une exception lorsque des informations sont perdues hors tolérance. Inversement, la version normale est ignorée même si des informations sont perdues.

int i = value.intValueExact();
long l = value.longValueExact();

Il existe également des versions «byte», «short» et «BigInteger» de la famille de méthodes «-ValueExact».

Comparaison de correspondance

Comparaison normale

Puisque BigDecimal # equals renvoie false si scale ne correspond pas, Si vous écrivez un système qui ne vous intéresse pas, tel que «scale», vous devez juger si le résultat de «compareTo» correspond à «0».

BigDecimal value1 = new BigDecimal("123.0"); // scale=1
BigDecimal value2 = new BigDecimal("123.00");// scale=2

System.out.println(value1.equals(value2));        // false

System.out.println(value1.compareTo(value2) == 0);// true

Utilisé pour la clé de HashMap

BigDecimal # equals BigDecimal # hashCode considère également scale, donc Écrire un système qui ne vous intéresse pas, tel que «scale», peut vous blesser.

BigDecimal value1 = new BigDecimal("123.0"); // scale=1
BigDecimal value2 = new BigDecimal("123.00");// scale=2

Map<BigDecimal, String> map = new HashMap<>();
map.put(value1, "data");

System.out.println(map.get(value2));// null

Dans ce cas, vous voudrez peut-être stabiliser scale avec BigDecimal # stripTrailingZeros.

BigDecimal value1 = new BigDecimal("123.0"); // scale=1
BigDecimal value2 = new BigDecimal("123.00");// scale=2

Map<BigDecimal, String> map = new HashMap<>();
map.put(value1.stripTrailingZeros(), "data");

System.out.println(map.get(value2.stripTrailingZeros()));// data

RoundingMode

RoundingMode est défini par ʻenum`, et il y a diverses choses telles que" arrondir "," arrondir vers le bas "," arrondir à l'infini positif "et" arrondir à l'infini négatif "en plus de" arrondir ", donc javadoc une fois. Je pense que tu devrais vérifier ça.

Ce qui suit est une transcription de Rounding Mode javadoc.

CEILING C'est un mode à rouler pour approcher l'infini positif. DOWN Ce mode s'arrondit pour approcher 0. FLOOR C'est un mode à rouler pour approcher l'infini négatif. HALF_DOWN Il s'agit d'un mode d'arrondi qui arrondit au "nombre le plus proche" (si les nombres des deux côtés sont égaux, ils sont tronqués). HALF_EVEN Mode d'arrondi pour arrondir au "nombre le plus proche" (cependant, si les nombres des deux côtés sont à distances égales, arrondissez au côté pair). HALF_UP Mode d'arrondi pour arrondir au «nombre le plus proche» (cependant, si les nombres des deux côtés sont égaux, arrondissez). UNNECESSARY Un mode d'arrondi qui indique que le résultat de l'opération requise est précis et ne nécessite pas d'arrondi. UP Ce mode arrondit à 0.

Les méthodes qui peuvent être remplacées par RoundingMode ne sont pas disponibles

N'utilisez pas le système BigDecimal # ROUND_ ~ et les méthodes qui supposent l'utilisation de ceux-ci. (@ Déprécié dans Java 9) Il devrait y avoir une paire de méthodes qui utilisent RoundingMode pour chacune, alors utilisons-les.

La méthode qui est devenue «@ obsolète» dans 9 est un héritage de l'ère 1.4. Cependant, quand je cherche habituellement sur Google avec "BigDecimal division", je suis désespéré parce que toutes les pages utilisant "BigDecimal.ROUND_HALF_UP" sortent.

Recommended Posts

[Java] Utilisez correctement Big Decimal ~ 2018 ~
Java Big Decimal
Comment utiliser Big Decimal
[Java] Utilisez Collectors.collectingAndThen
[Ruby] Big Decimal et DECIMAL
Grand décimal à Kotlin
Utiliser OpenCV avec Java
Utiliser PreparedStatement en Java
[java] Nombre de déclin → nombre n-aire nombre n-aire → nombre décimal
Utilisation correcte de la classe abstraite et de l'interface en Java
Utiliser des couches Lambda avec Java
Comment utiliser java Facultatif
Comment utiliser la classe Java
[Java] Comment utiliser removeAll ()
Comment utiliser Java Map
[java] Raisons d'utiliser statique
Comment utiliser les variables Java
Application Java CICS-Run - (5) Utiliser JCICSX
Utiliser SpatiaLite avec Java / JDBC
Comment utiliser HttpClient de Java (Get)
Utiliser java avec MSYS et Cygwin
Utiliser Microsoft Graph avec Java standard
Comment utiliser HttpClient de Java (Post)
[Java] Comment utiliser la méthode de jointure
Utilisons Twilio en Java! (Introduction)
Utiliser Azure Bing SpellCheck avec Java
Utilisez JDBC avec Java et Scala.
[Java] N'utilisez pas "+" dans append!
Utilisez des clés composites dans Java Maps.
Utiliser Java 11 avec Google Cloud Functions
java (utilisez le type de classe pour le champ)
Utiliser Chrome Headless de Selenium / Java
[JavaFX] [Java8] Comment utiliser GridPane
[Note] Gestion des points décimaux Java
Comment utiliser les méthodes de classe [Java]
[Java] Comment utiliser List [ArrayList]
Comment utiliser les classes en Java?
[Traitement × Java] Comment utiliser les tableaux
Comment utiliser les expressions Java lambda
Utilisez-vous Stream en Java?
[Java] Comment utiliser la classe Math
Comment utiliser le type enum Java
[Java] Conseils et problèmes d'erreur lors de la conversion du double en grand décimal
Empêcher la notation d'exposant (E) d'apparaître lorsque toString of Java Big Decimal