Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using BigDecimal to work with currencies

I was trying to make my own class for currencies using longs, but apparently I should use BigDecimal instead. Could someone help me get started? What would be the best way to use BigDecimals for dollar currencies, like making it at least but no more than 2 decimal places for the cents, etc. The API for BigDecimal is huge, and I don't know which methods to use. Also, BigDecimal has better precision, but isn't that all lost if it passes through a double? if I do new BigDecimal(24.99), how will it be different than using a double? Or should I use the constructor that uses a String instead?

like image 485
mk12 Avatar asked Aug 31 '09 23:08

mk12


People also ask

What data type should be used for currency in Java?

1 Answer. Java has Currency class that represents the ISO 4217 currency codes. BigDecimal is the best type for representing currency decimal values.

Why should we use BigDecimal?

The BigDecimal class provides operations on double numbers for arithmetic, scale handling, rounding, comparison, format conversion and hashing. It can handle very large and very small floating point numbers with great precision but compensating with the time complexity a bit.

What can I use instead of BigDecimal?

If you need to use division in your arithmetic, you need to use double instead of BigDecimal.


2 Answers

Here are a few hints:

  1. Use BigDecimal for computations if you need the precision that it offers (Money values often need this).
  2. Use the NumberFormat class for display. This class will take care of localization issues for amounts in different currencies. However, it will take in only primitives; therefore, if you can accept the small change in accuracy due to transformation to a double, you could use this class.
  3. When using the NumberFormat class, use the scale() method on the BigDecimal instance to set the precision and the rounding method.

PS: In case you were wondering, BigDecimal is always better than double, when you have to represent money values in Java.

PPS:

Creating BigDecimal instances

This is fairly simple since BigDecimal provides constructors to take in primitive values, and String objects. You could use those, preferably the one taking the String object. For example,

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

Displaying BigDecimal instances

You could use the setMinimumFractionDigits and setMaximumFractionDigits method calls to restrict the amount of data being displayed.

NumberFormat usdCostFormat = NumberFormat.getCurrencyInstance(Locale.US); usdCostFormat.setMinimumFractionDigits( 1 ); usdCostFormat.setMaximumFractionDigits( 2 ); System.out.println( usdCostFormat.format(displayVal.doubleValue()) ); 
like image 96
Vineet Reynolds Avatar answered Oct 07 '22 08:10

Vineet Reynolds


I would recommend a little research on Money Pattern. Martin Fowler in his book Analysis pattern has covered this in more detail.

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();     }    } 

Coming to the usage:

You would represent all monies using Money object as opposed to BigDecimal. Representing money as big decimal will mean that you will have the to format the money every where you display it. Just imagine if the display standard changes. You will have to make the edits all over the place. Instead using the Money pattern you centralize the formatting of money to a single location.

Money price = Money.dollars(38.28); System.out.println(price); 
like image 37
Brad Avatar answered Oct 07 '22 09:10

Brad