117 votes

BigDecimal - utiliser new ou valueOf

Je suis tombé sur deux façons d'obtenir un objet BigDecimal à partir d'un double d.

  1. new BigDecimal(d)
  2. BigDecimal.valueOf(d)

Quelle serait la meilleure approche ? Est-ce que valueOf créer un nouvel objet ?

En général (pas seulement pour BigDecimal), qu'est-ce qui est recommandé - new ou valueOf ?

10 votes

En général, valueOf est préférable (parce qu'il permet d'éviter de créer de nouveaux objets en réutilisant des instances "populaires"), mais dans le cas de BigDecimals et de double, malheureusement, les deux méthodes produisent des résultats différents, vous devez donc choisir celle dont vous avez besoin.

190voto

Joachim Sauer Points 133411

Ce sont deux questions distinctes : "Que dois-je utiliser pour BigDecimal ?" et "Que dois-je faire en général ?"

Pour BigDecimal : c'est un peu délicat, parce qu'elles ne faites pas la même chose . BigDecimal.valueOf(double) utilisera le canonique String représentation de la double transmise pour instancier le BigDecimal objet. En d'autres termes : La valeur de l'objet BigDecimal sera ce que vous verrez quand vous ferez System.out.println(d) .

Si vous utilisez new BigDecimal(d) cependant, alors le BigDecimal tentera de représenter le double valeur de manière aussi précise que possible . Cela permettra généralement entraîne le stockage de beaucoup plus de chiffres que vous ne le souhaitez. Strictement parlant, c'est plus correct que valueOf() mais c'est beaucoup moins intuitif.

Il y a une bonne explication à ce sujet dans la JavaDoc :

Les résultats de ce constructeur peuvent être quelque peu imprévisibles. On pourrait supposer qu'écrire new BigDecimal(0.1) en Java crée un BigDecimal qui est exactement égal à 0,1 (une valeur non échelonnée de 1, avec une échelle de 1), mais il est en fait égal à 0,100000000000055511151231257827021181583404541015625. Cela est dû au fait que 0,1 ne peut pas être représenté exactement comme un double (ou, d'ailleurs, comme une fraction binaire de longueur finie). Ainsi, la valeur qui est transmise au constructeur n'est pas exactement égale à 0,1, malgré les apparences.

En général, si le résultat est le même (c'est-à-dire pas dans le cas de BigDecimal mais dans la plupart des autres cas), alors valueOf() devrait être préférée : elle permet de mettre en cache des valeurs communes (comme on le voit sur Integer.valueOf() ) et il peut même modifier le comportement de la mise en cache sans que l'appelant doive être modifié. new sera toujours instancier une nouvelle valeur, même si ce n'est pas nécessaire (meilleur exemple : new Boolean(true) contra. Boolean.valueOf(true) ).

51voto

DuncanKinnear Points 1062

Si vous utilisez votre BigDecimal pour stocker des valeurs monétaires, je vous recommande vivement de le faire. PAS n'impliquent aucune valeur double dans leurs calculs.

Comme indiqué dans une autre réponse, il y a des problèmes de précision connus avec les valeurs doubles et ils reviendront vous hanter.

Une fois que vous avez dépassé ce stade, la réponse à votre question est simple. Utilisez toujours la méthode du constructeur avec la valeur String comme argument du constructeur, car il n'y a pas d'argument de type valueOf méthode pour String .

Si vous voulez des preuves, essayez ce qui suit :

BigDecimal bd1 = new BigDecimal(0.01);
BigDecimal bd2 = new BigDecimal("0.01");
System.out.println("bd1 = " + bd1);
System.out.println("bd2 = " + bd2);

Vous obtiendrez le résultat suivant :

bd1 = 0.01000000000000000020816681711721685132943093776702880859375
bd2 = 0.01

Voir aussi Question connexe

6voto

Dr. UnitTest Points 138

En fait, valueOf(double val) fait simplement cela :

return new BigDecimal(Double.toString(val));

Donc -> oui, un nouvel objet sera créé :).

En général, je pense que cela dépend de votre style de codage. Je ne mélangerais pas valueOf et "new", si les deux aboutissent au même résultat.

8 votes

Techniquement vrai, mais : ça fera un énorme différence. valueOf() a le plus intuitif comportement, tandis que new BigDecimal(d) a le plus correct un. Essayez les deux et voyez la différence.

0 votes

Techniquement faux. Le mot clé 'new' crée toujours un nouvel objet alors que la javadoc ne dit pas si valueOf retournera toujours un nouvel objet ou non. Ce n'est pas le cas, pas toujours. Il a quelques valeurs dans le cache donc new BigDecimal(1) != new BigDecimal(1) mais BigDecimal.valueOf(1) == BigDecimal.valueOf(1)

1 votes

@user : oui, mais depuis BigDecimal est immuable, il doit être traité de la même manière que les wrappers primitifs ( Integer , Byte , ...) et String sont traitées : identité de l'objet ne devrait pas avoir d'importance à votre code, seul le valeur devrait avoir de l'importance.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X