How to calculate money in Java
Short answer
double stores decimal numbers approximately, so money is handled with BigDecimal:
void main() {
IO.println(0.1 + 0.2);
IO.println(new BigDecimal("0.10").add(new BigDecimal("0.20")));
}Output:
0.30000000000000004
0.30Arithmetic
The + and * operators do not work with BigDecimal — you need methods. Each method returns a new number:
void main() {
var price = new BigDecimal("19.99");
var quantity = BigDecimal.valueOf(3);
var discount = new BigDecimal("5.00");
var total = price.multiply(quantity).subtract(discount);
IO.println(total);
}Output:
54.97Tax with rounding
After multiplying by a percentage you get more digits — round to cents:
void main() {
var net = new BigDecimal("49.99");
var vat = net.multiply(new BigDecimal("0.19"));
IO.println(vat);
IO.println(vat.setScale(2, RoundingMode.HALF_UP));
}Output:
9.4981
9.50Division
When dividing, specify the scale and the rounding rule, otherwise an endless fraction throws an exception:
void main() {
var bill = new BigDecimal("100.00");
var share = bill.divide(BigDecimal.valueOf(3), 2, RoundingMode.HALF_UP);
IO.println(share);
}Output:
33.33Comparison
equals() takes the number of decimal places into account, while compareTo() looks only at the value:
void main() {
var a = new BigDecimal("2.0");
var b = new BigDecimal("2.00");
IO.println(a.equals(b));
IO.println(a.compareTo(b) == 0);
}Output:
false
trueCommon mistake
Creating a BigDecimal from a double. The inaccuracy of the double is carried over completely:
void main() {
IO.println(new BigDecimal(0.1));
IO.println(new BigDecimal("0.1"));
IO.println(BigDecimal.valueOf(0.1));
}Output:
0.1000000000000000055511151231257827021181583404541015625
0.1
0.1Create it from a string or with BigDecimal.valueOf().
Functions used in this recipe
- BigDecimal — An exact decimal number — for money and calculations where double rounding errors are unacceptable.