Rappresentazione dei valori monetari in Java [chiuso]


94

Capisco che BigDecimal è la best practice consigliata per rappresentare i valori monetari in Java. Cosa usi? Esiste una libreria migliore che preferisci utilizzare?


4
dai un'occhiata a JSR 354
yegor256

1
Ecco una classe di valuta che puoi copiare ed estendere: java-articles.info/articles/?p=254
Gilbert Le Blanc

Vedi anche l'implementazione di riferimento di JSR-354 github.com/JavaMoney/jsr354-ri
battuta il

Risposte:


81

BigDecimalfino in fondo. Ho sentito di alcune persone che creano le proprie Casho Moneyclassi che incapsulano un valore in contanti con la valuta, ma sotto la pelle è ancora un BigDecimal, probabilmente con BigDecimal.ROUND_HALF_EVENarrotondamento.

Modifica: come Don menziona nella sua risposta , ci sono progetti open source come timeandmoney , e mentre li applaudo per aver cercato di impedire agli sviluppatori di dover reinventare la ruota, non ho abbastanza fiducia in una libreria pre-alpha da usare in un ambiente di produzione. Inoltre, se scavi sotto il cofano, vedrai che usano BigDecimalanche loro .


4
+1. Abbiamo deciso di aggiungere anche una classe contenitore che consuma una valuta. Ciò è utile durante il rendering di valori monetari nelle tabelle.
Daniel Hiller

1
sì, questo è un approccio abbastanza comune e ha molto senso. Un avvertimento a questo è quando hai a che fare con lo yen giapponese, poiché non hanno una denominazione di valuta minore come i centesimi, quindi ha bisogno delle sue regole di arrotondamento.
ninesided

3
@ninesided offre un ottimo esempio del perché rotolare il tuo è una cattiva risposta. "Oh, a proposito, non funziona per $ CURRENCY_X." Questo è un buon segno che non funziona nemmeno per molte altre valute.
James Moore

1
@JamesMoore Non sono d'accordo sul fatto che "rotolare il tuo" sia un approccio sbagliato, devi solo essere consapevole dei possibili limiti dell'approccio che scegli, da qui il motivo per cui lo menziono. È banale implementare regole di arrotondamento diverse per valuta, ma se il tuo sistema deve trattare solo in USD o EUR, non è necessario ingegnerizzare troppo le cose.
ninesided

1
Dai un'occhiata a stackoverflow.com/questions/5134237/… per un solo motivo per cui BigDecimal è un problema. La contabilità globale è solo una palude di casi speciali, e cercare di spazzarli tutti sotto il tappeto di BigDecimal non funziona.
James Moore



8

Una comoda libreria in cui mi sono imbattuto in precedenza è la libreria Joda-Money . Una delle sue implementazioni è infatti basata su BigDecimal. Si basa sulla specifica ISO-4217 per le valute e può supportare un elenco di valute personalizzato (caricato tramite CVS).

Questa libreria ha un numero limitato di file che è possibile consultare rapidamente se sono necessarie modifiche. Joda-Money è pubblicato con la licenza Apache 2.0.


7

Se stai usando solo dollari e centesimi, userei un long (offset di 2 cifre decimali). Se hai bisogno di maggiori dettagli, il decimale grande potrebbe essere la strada da percorrere.

Ad ogni modo, probabilmente estenderei la classe per avere un .toString () che utilizza il formato corretto e come luogo in cui inserire altri metodi che potrebbero emergere (per molto tempo, la moltiplicazione e la divisione andranno storte se il decimale non è non è aggiustato)

Inoltre, se si utilizza definire la propria classe e interfaccia, è possibile sostituire l'implementazione a piacimento.


2
Attenzione, anche il lungo potrebbe essere troppo breve per contenere il debito federale degli Stati Uniti in centesimi ... se non ora, tra pochi anni.
Ingo

3
Sono d'accordo - qualsiasi numero enorme di dollari (o forse se stai monitorando denaro in yen) dovresti usare BigDecimal - ma anche in questo caso prenderei seriamente in considerazione l'utilizzo di una classe contenitore per questo. Penso che la maggior parte della complessità della programmazione provenga da persone che non definiscono classi piccole e semplici attorno a raccolte e tipi intrinseci.
Bill K

3

BigDecimal o un'altra rappresentazione a punto fisso è ciò che è generalmente necessario per il denaro.

Le rappresentazioni e i calcoli in virgola mobile ( Double, Float) non sono esatti e portano a risultati errati.


7
A rigor di termini, anche BigDecimal è inesatto; corrisponde semplicemente meglio all'arrotondamento decimale a cui siamo abituati nella vita quotidiana e consente di specificare le modalità di arrotondamento.
Michael Borgwardt

1
@Michael Borgwardt BigDecimal differisce da IEEE FP in quanto è specificata una scala esplicita. Sebbene non tutte le operazioni siano esatte, ciò garantisce che un insieme di operazioni e comportamenti sia sempre esatto e la scala sia costante mentre la scala per IEEE FP diminuisce con il valore.

1
Cosa c'entra questo con i soldi? Le organizzazioni contabili di tutto il mondo di solito hanno requisiti molto specifici su come eseguire la matematica nella loro valuta. BigDecimal corrisponde esattamente a ciascuno di questi standard? Lo farà il prossimo anno, quando questi standard cambieranno? E BigDecimal non si avvicina nemmeno a specificare utili regole di arrotondamento per le valute.
James Moore

2

Devi stare molto attento quando hai a che fare con tempo e denaro.

Quando lavori con i soldi, spero che tutti sappiano di non usare mai un galleggiante o un doppio.

Ma non sono sicuro di BigDecimal.

Nella maggior parte dei casi starai bene se tieni traccia dei centesimi in un int o in un lungo. In questo modo non hai mai a che fare con una cifra decimale.

Visualizzi solo i dollari quando lo stampi. Lavora sempre con i centesimi interni usando numeri interi. Questo può essere complicato se è necessario dividere o utilizzare Math.abs ().

Tuttavia, potrebbe interessarti mezzo centesimo, o anche un centesimo di centesimo. Non so quale sia un buon modo per farlo. Potrebbe essere necessario gestire solo il millesimo di centesimi e utilizzare un lungo. O forse sarai costretto a usare BigDecimal

Vorrei leggere molto di più su questo, ma ignora tutti coloro che iniziano a parlare di usare un galleggiante o un doppio per rappresentare il denaro. Chiedono solo guai.

Sento che il mio consiglio non è completo, quindi per favore mettici di più. Hai a che fare con tipi pericolosi!


2
Perché dovresti essere "costretto" a usare BigDecimal? Di cosa non sei sicuro? È chiaramente superiore al lavoro con i centesimi, in quanto consente di specificare esplicitamente le modalità di arrotondamento.
Michael Borgwardt

1
@MichaelBorgwardt: sì, ti consente di specificare un piccolo sottoinsieme delle modalità di arrotondamento necessarie per le valute. Così? (Suggerimento: l'arrotondamento delle valute è deciso, di solito, dalle organizzazioni contabili nazionali. Sono perfettamente felici di lanciare in strani casi speciali. Vedere stackoverflow.com/questions/5134237/… per solo uno dei tanti motivi divertenti per cui l'arrotondamento BigDecimal è completamente inutile qui.)
James Moore

@ James: come è esattamente "inutile"? In che modo l'implementazione di questi casi speciali sarebbe più difficile con BigDecimal che con qualcos'altro?
Michael Borgwardt

1
OK, completamente inutile è troppo forte. Nella complicata classe che astrae la valuta, le regole di arrotondamento di BigDecimal sono probabilmente utili in alcuni casi specifici per costruire un sottoinsieme dei modi in cui avviene l'arrotondamento della valuta. Ma il caso generale è che le regole di arrotondamento per le valute richiedono meccanismi soggetti a modifiche nel tempo (poiché le agenzie contabili umane costituiscono le regole e sono libere di cambiarle). La domanda non riguarda gli euro (o qualunque cosa sostituisca gli euro il mese prossimo ...), o i dollari nel 2011, si tratta di valuta, quindi devi affrontare una grande complessità.
James Moore

2

Creare una classe Money è la strada da percorrere. Utilizzando BigDecimal (o anche un int) sotto. Quindi utilizzando la classe Currency per definire la convenzione di arrotondamento.

Sfortunatamente, senza l'overload da parte dell'operatore di Java, creare tipi di base di questo tipo è piuttosto sgradevole.


2

C'è una libreria migliore, tempo e denaro . IMO, è di gran lunga superiore alle librerie fornite dal JDK per rappresentare questi 2 concetti.


3
Questa risposta è stata pubblicata tre anni fa. Oggi, il progetto timeandmoney è ancora pre-alpha secondo quel collegamento.
James Moore

1
@JamesMoore Buona chiamata. La risposta ha ormai 7 anni e il progetto non è ancora stabile.
Navin

1

Sicuramente non BigDecimal. Ci sono così tante regole speciali per l'arrotondamento e la presentazione di cui devi preoccuparti.

Martin Fowler consiglia l'implementazione di una classe Money dedicata per rappresentare gli importi in valuta e che implementa anche le regole per la conversione di valuta.


6
e il tipo di dati sottostante della sua classe Money? BigDecimal.
ninesided

1
Non è vero. Potresti usare Integer nella classe soldi, che è ciò che fa Martin. L'ho fatto molte volte.
egervari

La raccomandazione è corretta però; i calcoli che coinvolgono il denaro sono una vasta palude di casi speciali che cambiano nel tempo. BigDecimal può essere utile come una piccola parte della soluzione, ma non è certamente generale.
James Moore

1

Ehi, ecco un articolo molto interessante su BigDecimal e un esempio illustrativo del motivo per cui a volte viene utilizzato al posto dei doppi. Tutorial BigDecimal .


0

È possibile utilizzare la classe DecimalFormat quando alla fine si visualizza un valore di valuta. Fornisce supporto per la localizzazione ed è abbastanza estensibile.


0

Incapsulerei BigDecimal nella classe Money che ha anche una valuta proprio come qualcuno menzionato sopra. La cosa importante è che tu faccia una quantità estrema di unit test e soprattutto se lavori con valute diverse. Inoltre è una buona idea se aggiungi un costruttore conveniente che accetta una stringa o un metodo factory che fa lo stesso in modo che tu possa scrivere i tuoi test in questo modo:

   assertEquals(Money.create("100.0 USD").add("10 GBP"),Money.create("116 USD"));

0

Ci sono sempre vincoli e specifiche coinvolte. Chiunque non abbia esperienza sufficiente per apprezzare le sottili questioni delineate nel seguente articolo dovrebbe riconsiderare seriamente prima di trattare i dati finanziari del mondo reale:

http://lemnik.wordpress.com/2011/03/25/bigdecimal-and-your-money

BigDecimal non è certo l'unica rappresentazione corretta o l'unico pezzo del puzzle. Date alcune condizioni, l'utilizzo di una classe Money supportata da centesimi memorizzati come numero intero potrebbe essere sufficiente e sarebbe molto più veloce di BigDecimal. Sì, ciò implica l'uso del dollaro come valuta e limita gli importi, ma tali vincoli sono perfettamente accettabili per molti casi d'uso e tutte le valute hanno comunque casi speciali per arrotondamenti e sottodenominazioni, quindi non esiste una soluzione "universale".


1
Questo sembra essere un commento su un altro post invece di una risposta effettiva. È anche eccessivamente al vetriolo. Per favore, cerca di essere più civile in futuro.
Slater Victoroff
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.