BackendBench
Coffee

Unravel โ€บ Java concepts โ€บ Numbers and math

Java language

BigDecimal and money

BigDecimal stores decimal numbers exactly, so it is used for money.

๐Ÿ”Ž Unravel this example

At a glance

Mental model

Counting coins exactly versus measuring money with a ruler that is slightly off at every mark.

What happens, in order
  1. 1Create from strings or valueOf, never from a double: new BigDecimal("0.10"), not new BigDecimal(0.1) (which carries the binary error)
  2. 2Arithmetic returns new objects: a.add(b), a.multiply(b)Division needs a scale and a rounding mode, or it throws when the result does not terminate.
  3. 3Compare with compareTo, not equals: 2.0 and 2.00 are different to equals (different scale) but equal to compareTo
  4. 4setScale(2, RoundingMode.HALF_EVEN) fixes the number of decimals and says how to roundDo this once, at the boundary where an amount is stored or shown, and not after every intermediate step.
  5. 5To print without scientific notation use toPlainString(); stripTrailingZeros() removes zeros that only record precision, but it can turn 100 into 1E+2, so format afterwards
Remember
Watch out
new BigDecimal(double)equals instead of compareToDividing without a rounding modeUsing double for money
Example (highlighted lines explain it)
BigDecimal price = new BigDecimal("19.99");BigDecimal total = price.multiply(BigDecimal.valueOf(3));BigDecimal tax = total.multiply(new BigDecimal("0.18")).setScale(2, RoundingMode.HALF_EVEN);boolean same = total.compareTo(new BigDecimal("59.970")) == 0;
  1. line 1 uses BigDecimal, the core of BigDecimal and money
  2. line 2 uses BigDecimal, the core of BigDecimal and money
  3. line 3 uses BigDecimal, the core of BigDecimal and money
  4. line 4 uses BigDecimal, the core of BigDecimal and money
Read the full explanation (about 1 min)

BigDecimal stores decimal numbers exactly, so it is used for money. double cannot represent 0.1 exactly, and the error shows up in totals.

A mental model

Counting coins exactly versus measuring money with a ruler that is slightly off at every mark.

How it works

Create from strings or valueOf, never from a double: new BigDecimal("0.10"), not new BigDecimal(0.1) (which carries the binary error).

Arithmetic returns new objects: a.add(b), a.multiply(b). Division needs a scale and a rounding mode, or it throws when the result does not terminate.

Compare with compareTo, not equals: 2.0 and 2.00 are different to equals (different scale) but equal to compareTo.

setScale(2, RoundingMode.HALF_EVEN) fixes the number of decimals and says how to round. Do this once, at the boundary where an amount is stored or shown, and not after every intermediate step.

To print without scientific notation use toPlainString(); stripTrailingZeros() removes zeros that only record precision, but it can turn 100 into 1E+2, so format afterwards.

Going deeper

Pick the rounding mode on purpose (HALF_EVEN is common for finance, HALF_UP for what people learn at school). Store money in the smallest unit as long cents as an alternative, and never mix currencies in one number.

Under the hood

A BigDecimal is an unscaled BigInteger plus an int scale: the value is unscaled times 10 to the minus scale.

Common mistakes

  • new BigDecimal(double).
  • equals instead of compareTo.
  • Dividing without a rounding mode.
  • Using double for money.

How Unravel recognises it

When you paste code, Unravel looks for these signs of bigdecimal and money. Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Frequently asked questions

What is BigDecimal and money?

BigDecimal stores decimal numbers exactly, so it is used for money. double cannot represent 0.1 exactly, and the error shows up in totals.

What are the most common mistakes with BigDecimal and money?

new BigDecimal(double). equals instead of compareTo. Dividing without a rounding mode. Using double for money.

How can I see BigDecimal and money in real code?

Paste your own Java into Unravel and it will point out where bigdecimal and money appears, explain how it works at the detail level you choose, and draw the flow of the code around it.