72 votes

Utiliser BigDecimal pour travailler avec des devises

J'ai essayé de faire ma propre classe pour les devises à l'aide de la nostalgie, mais Apparemment je dois utiliser BigDecimal (et puis à chaque fois que je l'imprimer, il suffit d'ajouter le signe $ devant elle). Quelqu'un pourrait-il svp me faire? Quelle serait la meilleure façon d'utiliser BigDecimals pour le Dollar, comme ça au moins, mais pas plus de 2 décimales pour le cents, etc. L'api pour BigDecimal est énorme, et je ne sais pas les méthodes à utiliser. Aussi, BigDecimal a une meilleure précision, mais n'est-ce pas tout perdu si elle passe à travers un double? si je ne nouveau BigDecimal(24.99), comment est-il différent que d'utiliser un double? Ou devrais-je utiliser le constructeur qui utilise un String à la place?

EDIT: j'ai décidé d'utiliser BigDecimals, et ensuite utiliser:

private static final java.text.NumberFormat moneyt =
        java.text.NumberFormat.getCurrencyInstance();
{
    money.setRoundingMode(RoundingMode.HALF_EVEN);
}

et puis à chaque fois que j'affiche le BigDecimals, utiliser money.format(theBigDecimal). Est-ce bien? Je devrais avoir l' BigDecimal arrondi-il trop? Parce qu'alors, il n'a pas obtenir de l'arrondi avant qu'elle ne fasse une autre opération.. si oui, pourriez-vous me montrer comment faire? Et comment dois-je créer l' BigDecimals? new BigDecimal("24.99") ?

Eh bien, après de nombreux commentaires de Vineet Reynolds (merci de garder de revenir et de répondre), c'est ce que j'ai décidé. J'utilise BigDecimals et NumberFormat. C'est là que j'ai créer l' NumberFormat de l'instance.

private static final NumberFormat money;
static {
    money = NumberFormat.getCurrencyInstance(Locale.CANADA);
    money.setRoundingMode(RoundingMode.HALF_EVEN);
}

Voici mon BigDecimal:

private final BigDecimal price;

Chaque fois que je veux afficher l' price, ou d'une autre, BigDecimal que j'ai obtenu grâce à des calculs de price, j'utilise:

money.format(price)

pour obtenir l' String. Chaque fois que je veux stocker l' price, ou d'un calcul à partir d' price, dans une base de données ou dans un domaine ou n'importe où, j'utilise (de champ):

myCalculatedResult = price.add(new BigDecimal("34.58")).setScale(2, RoundingMode.HALF_EVEN);

.. mais je pense que maintenant peut-être que je ne devrais pas avoir l' NumberFormat tour, mais quand je veux afficher cela:

System.out.print(money.format(price.setScale(2, RoundingMode.HALF_EVEN);

Cette façon de s'assurer que le modèle et les choses affiché dans la vue sont les mêmes. Je ne fais pas:

price = price.setScale(2, RoundingMode.HALF_EVEN);

Car alors il serait toujours arrondis à 2 décimales et de ne pas être aussi précis dans les calculs.

Donc le tout résolu maintenant, je suppose. Mais est-il un raccourci saisissant calculatedResult.setScale(2, RoundingMode.HALF_EVEN) de tous les temps? Tout ce que je peux penser est statique de l'importation de HALF_EVEN...

EDIT: j'ai changé mon esprit un peu, je pense que si je stocker une valeur, je ne vais pas autour d'elle, à moins que je n'ai plus d'activités à faire avec elle, par exemple, si le total final qui sera facturé à quelqu'un. Je ne tour des choses à la fin, ou chaque fois que nécessaire, et je vais encore utiliser NumberFormat de la monnaie mise en forme, mais depuis j'ai toujours envie d'arrondi pour l'affichage, j'ai fait une méthode statique pour l'affichage:

public static String moneyFormat(BigDecimal price) {
    return money.format(price.setScale(2, RoundingMode.HALF_EVEN));
}

De sorte que les valeurs stockées dans les variables ne seront pas arrondis, et je vais utiliser cette méthode pour afficher les prix.

88voto

Vineet Reynolds Points 40529

Voici quelques conseils:

  1. Utiliser BigDecimal pour les calculs si vous avez besoin de la précision qu'il propose (les valeurs de la monnaie souvent besoin de cela).
  2. Utiliser l' NumberFormat classe pour l'affichage. Cette classe va prendre soin de problèmes de localisation pour des montants en devises différentes. Toutefois, il faudra que dans les primitives; par conséquent, si vous pouvez accepter le petit changement de précision en raison de la transformation de l' double, vous pouvez utiliser cette classe.
  3. Lors de l'utilisation de l' NumberFormat classe, l'utilisation de l' scale() méthode sur l' BigDecimal exemple pour définir la précision et la méthode d'arrondi.

PS: Au cas où vous vous poseriez la question, BigDecimal est toujours mieux que d' double, lorsque vous avez à représenter les valeurs de la monnaie en Java.

PPS:

La création d' BigDecimal cas

C'est assez simple, puisqu' BigDecimal fournit les constructeurs à prendre des valeurs primitives, et String objets. Vous pouvez utiliser ces, de préférence celui qui prend l' String objet. Par exemple,

BigDecimal modelVal = new BigDecimal("24.455");
BigDecimal displayVal = modelVal.setScale(2, RoundingMode.HALF_EVEN);

Affichage BigDecimal cas

Vous pouvez utiliser l' setMinimumFractionDigits et setMaximumFractionDigits des appels de méthode pour limiter la quantité de données affichées.

NumberFormat usdCostFormat = NumberFormat.getCurrencyInstance(Locale.US);
usdCostFormat.setMinimumFractionDigits( 1 );
usdCostFormat.setMaximumFractionDigits( 2 );
System.out.println( usdCostFormat.format(displayVal.doubleValue()) );

40voto

Brad Points 131

Je vous recommande un peu de recherche sur l'Argent Motif. Martin Fowler dans son livre l'Analyse de modèle a traité de ce sujet plus en détail.

public class Money {

    private static final Currency USD = Currency.getInstance("USD");
    private static final RoundingMode DEFAULT_ROUNDING = RoundingMode.HALF_EVEN;

    private BigDecimal amount;
    private Currency currency;   

    public static Money dollars(BigDecimal amount) {
        return new Money(amount, USD);
    }

    Money(BigDecimal amount, Currency currency) {
        this(amount, currency, DEFAULT_ROUNDING);
    }

    Money(BigDecimal amount, Currency currency, RoundingMode rounding) {
        this.amount = amount;
        this.currency = currency;

        this.amount = amount.setScale(currency.getDefaultFractionDigits(), rounding);
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public Currency getCurrency() {
        return currency;
    }

    @Override
    public String toString() {
        return getCurrency().getSymbol() + " " + getAmount();
    }

    public String toString(Locale locale) {
        return getCurrency().getSymbol(locale) + " " + getAmount();
    }   
}

Venir à l'utilisation:

Vous représenter tout l'argent à l'aide de Money objet par opposition à l' BigDecimal. Représentant d'argent aussi importante virgule signifie que vous aurez le format de l'argent chaque endroit où vous l'afficher. Imaginez si l'affichage standard des changements. Vous aurez à effectuer les modifications dans tous les sens. Au lieu d'utiliser l' Money modèle vous permettant de centraliser la mise en forme de l'argent à un seul endroit.

Money price = Money.dollars(38.28);
System.out.println(price);

11voto

Victor Grazi Points 1326

Ou attendez JSR-354. L'API Java Money et Currency bientôt disponible!

1voto

Diego Dias Points 6879

1) Si vous êtes limité à l' double de précision, une raison d'utiliser BigDecimals est de réaliser des opérations avec l' BigDecimals créé à partir de l' doubles.

2) L' BigDecimal se compose d'une précision arbitraire entier non mis à l'échelle de la valeur et un non négatif entier de 32 bits de l'échelle, tandis que le double enveloppe une valeur de type primitif double dans un objet. Un objet de type Double contient un seul champ dont le type est - double

3) Il ne doit pas faire de différence

Vous devriez avoir aucune difficulté avec l' $ et de précision. Une façon de le faire est d'utiliser System.out.printf

1voto

tim_wonil Points 1148

Utiliser BigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP) quand vous voulez arrondir à la décimale 2 points de pour cents. Être conscient de l'arrondissement d'erreur lorsque vous effectuez des calculs bien. Vous devez être cohérent quand vous allez faire l'arrondi de la valeur de l'argent. Soit faire les arrondis à la fin, juste une fois, après tous les calculs sont faits, ou de demander l'arrondissement à chaque valeur avant de faire les calculs. Celui qui à utiliser dépend de votre exigence de l'entreprise, mais en général, je pense que faire l'arrondi à droite à la fin qui semble faire un plus de sens pour moi.

Utiliser un String lorsque vous construisez BigDecimal de la valeur de l'argent. Si vous utilisez double, il aura une fuite en valeurs à virgule flottante à la fin. Cela est dû à l'architecture de l'ordinateur concernant la façon dont double/float les valeurs sont représentées dans un format binaire.

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