Usare BigDecimal per lavorare con le valute

Stavo cercando di creare la mia class per le valute usando long, ma a quanto pare dovrei usare BigDecimal . Qualcuno potrebbe aiutarmi a iniziare? Quale sarebbe il modo migliore di usare BigDecimal per le valute in dollari, come renderlo almeno ma non più di 2 cifre decimali per i centesimi, ecc. L’API per BigDecimal è enorme, e non so quali metodi usare. Inoltre, BigDecimal ha una precisione migliore, ma non è tutto perso se passa attraverso un double ? se faccio un nuovo BigDecimal(24.99) , come sarà diverso BigDecimal(24.99) un double ? O dovrei usare il costruttore che usa invece una String ?

Ecco alcuni suggerimenti:

  1. Usa BigDecimal per i calcoli se hai bisogno della precisione che offre (i valori monetari spesso hanno bisogno di questo).
  2. Utilizzare la class NumberFormat per la visualizzazione. Questa class si occuperà dei problemi di localizzazione per importi in diverse valute. Tuttavia, prenderà solo i primitivi; quindi, se puoi accettare il piccolo cambiamento di accuratezza dovuto alla trasformazione in double , puoi usare questa class.
  3. Quando si utilizza la class NumberFormat , utilizzare il metodo scale() BigDecimal per impostare la precisione e il metodo di arrotondamento.

PS: Se ti stavi chiedendo, BigDecimal è sempre meglio del double , quando devi rappresentare i valori monetari in Java .

PPS:

Creazione di istanze BigDecimal

Questo è abbastanza semplice poiché BigDecimal fornisce ai costruttori i valori primitivi e gli oggetti String . Potresti usare quelli, preferibilmente quello che prende l’object String . Per esempio,

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

Visualizzazione di istanze BigDecimal

È ansible utilizzare le chiamate del metodo setMinimumFractionDigits e setMaximumFractionDigits per limitare la quantità di dati visualizzati.

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

Consiglierei una piccola ricerca su Money Pattern. Martin Fowler nel suo libro Analysis pattern ha trattato questo in modo più dettagliato.

 public class Money { private static final Currency USD = Currency.getInstance("USD"); private static final RoundingMode DEFAULT_ROUNDING = RoundingMode.HALF_EVEN; private final BigDecimal amount; private final 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.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(); } } 

Venendo all’utilizzo:

Rappresenteresti tutti i soldi utilizzando l’object Money in contrapposizione a BigDecimal . Rappresentare il denaro come grande decimale significherà che avrai il formato per il denaro ogni dove lo visualizzi. Immagina solo se lo standard di visualizzazione cambia. Dovrai apportare le modifiche dappertutto. Usando invece il modello di Money , si centralizza la formattazione del denaro in un’unica posizione.

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

Oppure, aspetta JSR-354 . API Java Money and Currency in arrivo!

1) Se sei limitato alla double precisione, una ragione per usare BigDecimal è realizzare operazioni con i BigDecimal creati dalla double s.

2) Il BigDecimal consiste in un valore non BigDecimal intero arbitrario di precisione e una scala intera non negativa a 32 bit, mentre il doppio racchiude un valore del tipo primitivo double in un object. Un object di tipo Double contiene un singolo campo il cui tipo è double

3) Non dovrebbe fare alcuna differenza

Non dovresti avere difficoltà con $ e precisione. Un modo per farlo è usare System.out.printf

I tipi numerici primitivi sono utili per memorizzare singoli valori in memoria. Ma quando si ha a che fare con il calcolo usando i tipi double e float, c’è un problema con l’arrotondamento. Succede perché la rappresentazione della memoria non si adatta esattamente al valore. Ad esempio, si suppone che un doppio valore richieda 64 bit, ma Java non usa tutti i 64 bit. Memorizza solo ciò che ritiene le parti importanti del numero. Quindi puoi arrivare ai valori sbagliati quando aggiungi valori insieme di tipo float o double.

Si prega di vedere una breve clip https://youtu.be/EXxUSz9x7BM

Usa BigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP) quando vuoi arrotondare fino ai 2 punti decimali per centesimi. Essere consapevoli di arrotondare l’errore quando si fanno i calcoli però. Devi essere coerente quando farai l’arrotondamento del valore del denaro. Eseguire l’arrotondamento alla fine solo una volta dopo aver eseguito tutti i calcoli o applicare l’arrotondamento a ciascun valore prima di eseguire qualsiasi calcolo. Quale da usare dipenderà dal tuo fabbisogno aziendale, ma in generale, penso che arrotondare alla fine sembra avere un significato migliore per me.

Usa una String quando costruisci BigDecimal come valore monetario. Se si utilizza il double , alla fine avrà valori finali in virgola mobile. Ciò è dovuto all’architettura del computer riguardo a come i valori double / float sono rappresentati in formato binario.

C’è un ampio esempio di come farlo su javapractices.com. Vedi in particolare la class Money , che ha lo scopo di rendere i calcoli monetari più semplici rispetto all’utilizzo diretto di BigDecimal .

Il design di questa class Money scopo di rendere le espressioni più naturali. Per esempio:

 if ( amount.lt(hundred) ) { cost = amount.times(price); } 

Lo strumento WEB4J ha una class simile, chiamata Decimal , che è un po ‘più lucida della class Money .

 NumberFormat.getNumberInstance(java.util.Locale.US).format(num);