What data type should you use for money in Java?
-
2It depends of what operations you are going to do. Please offer more information. – eversor Nov 16 '11 at 08:33
-
@eversor Can you give me description of what data type should be used for different operations? – questborn Nov 16 '11 at 08:42
-
1Am doing calculations which requires me to accurately represent cents. – questborn Nov 16 '11 at 08:49
-
Are you able to foretell the bigest amount of money your app will need to handle? And, your calculations, are they going to be simple (aditions etc.) or more complex financial operations? – eversor Nov 16 '11 at 09:31
-
*"It is not currency accepting answers"* – MC Emperor Sep 30 '20 at 14:15
-
I cannot understand why it get closed, while [the question asking about what class should be used in C#](https://stackoverflow.com/questions/693372/what-is-the-best-data-type-to-use-for-money-in-c) is open with 498 up votes. – tsh Mar 13 '23 at 08:44
11 Answers
Java has Currency
class that represents the ISO 4217 currency codes.
BigDecimal
is the best type for representing currency decimal values.
Joda Money has provided a library to represent money.

- 60,927
- 15
- 95
- 117

- 87,898
- 29
- 167
- 228
-
8
-
26@Borat Sagdiyev [This is the reason why](http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems). Also, you can refer to [this](https://www.securecoding.cert.org/confluence/display/java/NUM04-J.+Do+not+use+floating-point+numbers+if+precise+computation+is+required). – Buhake Sindi Jun 30 '14 at 18:04
-
3@Borat: you can if you know what you're doing, see [this article](http://vanillajava.blogspot.com/2011/08/double-your-money-again.html) by Peter Lawrey. but it seems at least as big a hassle to do all the rounding as to use BigDecimals. – Nathan Hughes Jun 22 '15 at 14:55
-
69"If I had a dime for every time I've seen someone use FLOAT to store currency, I'd have $999.997634" -- Bill Karwin – Collin Krawll Jun 03 '18 at 20:53
You can use Money and Currency API (JSR 354). You can use this API in, provided you add appropriate dependencies to your project.
For Java 8, add the following reference implementation as a dependency to your pom.xml
:
<dependency>
<groupId>org.javamoney</groupId>
<artifactId>moneta</artifactId>
<version>1.0</version>
</dependency>
This dependency will transitively add javax.money:money-api
as a dependency.
You can then use the API:
package com.example.money;
import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.is;
import java.util.Locale;
import javax.money.Monetary;
import javax.money.MonetaryAmount;
import javax.money.MonetaryRounding;
import javax.money.format.MonetaryAmountFormat;
import javax.money.format.MonetaryFormats;
import org.junit.Test;
public class MoneyTest {
@Test
public void testMoneyApi() {
MonetaryAmount eurAmount1 = Monetary.getDefaultAmountFactory().setNumber(1.1111).setCurrency("EUR").create();
MonetaryAmount eurAmount2 = Monetary.getDefaultAmountFactory().setNumber(1.1141).setCurrency("EUR").create();
MonetaryAmount eurAmount3 = eurAmount1.add(eurAmount2);
assertThat(eurAmount3.toString(), is("EUR 2.2252"));
MonetaryRounding defaultRounding = Monetary.getDefaultRounding();
MonetaryAmount eurAmount4 = eurAmount3.with(defaultRounding);
assertThat(eurAmount4.toString(), is("EUR 2.23"));
MonetaryAmountFormat germanFormat = MonetaryFormats.getAmountFormat(Locale.GERMAN);
assertThat(germanFormat.format(eurAmount4), is("EUR 2,23") );
}
}
-
2What about serialization and saving into db? What format should be used for sending over wire? – Paweł Szczur Dec 07 '15 at 11:28
-
1I believe that Oracle dediced againts including Java Money in Java 9. Really a shame. But great answer. We still can use it with Maven – borjab Jan 07 '16 at 16:08
-
4Do you have a source for Oracle deciding against including Java Money in Java 9? – Abdull Jan 07 '16 at 16:24
-
1@PawełSzczur It depends what you use for serialization and persistence, but, for example, you can use [jackson-datatype-money](https://github.com/zalando/jackson-datatype-money) for Jackson and [Jadira](http://jadira.sourceforge.net/usertype.core/index.html) for Hibernate. – Dario Seidl Aug 12 '21 at 15:54
-
@Abdull there was talk about Java Money being included in the JDK but that never happened. I don't have a source from Oracle, but there is some info here: https://stackoverflow.com/a/53181704/401712 – Dario Seidl Aug 16 '21 at 12:26
-
An integral type representing the smallest value possible. In other words your program should think in cents not in dollars/euros.
This should not stop you from having the gui translate it back to dollars/euros.

- 146,994
- 96
- 417
- 335

- 47,288
- 5
- 68
- 106
-
-
5@eversor that would need over 20 million dollars most apps wouldn't need that much if they do a long will be sufficient as not even our govenrments handle enough mone to overflow that – ratchet freak Nov 16 '11 at 09:19
-
5
-
6Many banks handle far larger sums of money that $20,000,000 every day. This does not even take account of currencies like yen with large exchange rates to the dollar. Integer types may be best to avoid rounding problems although they get messy with interest and exchange rate calculations. However, depending on the application, you may need a 64-bit integer type. – Alchymist Mar 25 '15 at 12:34
-
Ideally microdollars, actually, as then if you do e.g $10/3 then the rounding error (3333.3 => 3333.0) doesn't affect the final value as much (in this case it doesn't impact the real value at all, although it's dangerous to assume that it never will). This is especially important if you're doing a lot of calculations in a row before your user sees the result, as the rounding errors will compound. – Chris Browne Jul 01 '18 at 09:50
-
Don't forget to consider developed country where they have so many zeroes for money – stuckedunderflow Jan 11 '19 at 03:16
-
2022 here. We now have cryptocurrencies that do not have any atomic lower bound. Good luck, fellow doomed programmer. – Hubert Grzeskowiak May 02 '22 at 13:16
BigDecimal can be used, good explanation of why to not use Float or Double can be seen here: Why not use Double or Float to represent currency?

- 1
- 1

- 2,857
- 22
- 15
JSR 354: Money and Currency API
JSR 354 provides an API for representing, transporting, and performing comprehensive calculations with Money and Currency. You can download it from this link:
JSR 354: Money and Currency API Download
The specification consists of the following things:
- An API for handling e. g. monetary amounts and currencies
- APIs to support interchangeable implementations
- Factories for creating instances of the implementation classes
- Functionality for calculations, conversion and formatting of monetary amounts
- Java API for working with Money and Currencies, which is planned to be included in Java 9.
- All specification classes and interfaces are located in the javax.money.* package.
Sample Examples of JSR 354: Money and Currency API:
An example of creating a MonetaryAmount and printing it to the console looks like this::
MonetaryAmountFactory<?> amountFactory = Monetary.getDefaultAmountFactory();
MonetaryAmount monetaryAmount = amountFactory.setCurrency(Monetary.getCurrency("EUR")).setNumber(12345.67).create();
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.getDefault());
System.out.println(format.format(monetaryAmount));
When using the reference implementation API, the necessary code is much simpler:
MonetaryAmount monetaryAmount = Money.of(12345.67, "EUR");
MonetaryAmountFormat format = MonetaryFormats.getAmountFormat(Locale.getDefault());
System.out.println(format.format(monetaryAmount));
The API also supports calculations with MonetaryAmounts:
MonetaryAmount monetaryAmount = Money.of(12345.67, "EUR");
MonetaryAmount otherMonetaryAmount = monetaryAmount.divide(2).add(Money.of(5, "EUR"));
CurrencyUnit and MonetaryAmount
// getting CurrencyUnits by locale
CurrencyUnit yen = MonetaryCurrencies.getCurrency(Locale.JAPAN);
CurrencyUnit canadianDollar = MonetaryCurrencies.getCurrency(Locale.CANADA);
MonetaryAmount has various methods that allow accessing the assigned currency, the numeric amount, its precision and more:
MonetaryAmount monetaryAmount = Money.of(123.45, euro);
CurrencyUnit currency = monetaryAmount.getCurrency();
NumberValue numberValue = monetaryAmount.getNumber();
int intValue = numberValue.intValue(); // 123
double doubleValue = numberValue.doubleValue(); // 123.45
long fractionDenominator = numberValue.getAmountFractionDenominator(); // 100
long fractionNumerator = numberValue.getAmountFractionNumerator(); // 45
int precision = numberValue.getPrecision(); // 5
// NumberValue extends java.lang.Number.
// So we assign numberValue to a variable of type Number
Number number = numberValue;
MonetaryAmounts can be rounded using a rounding operator:
CurrencyUnit usd = MonetaryCurrencies.getCurrency("USD");
MonetaryAmount dollars = Money.of(12.34567, usd);
MonetaryOperator roundingOperator = MonetaryRoundings.getRounding(usd);
MonetaryAmount roundedDollars = dollars.with(roundingOperator); // USD 12.35
When working with collections of MonetaryAmounts, some nice utility methods for filtering, sorting and grouping are available.
List<MonetaryAmount> amounts = new ArrayList<>();
amounts.add(Money.of(2, "EUR"));
amounts.add(Money.of(42, "USD"));
amounts.add(Money.of(7, "USD"));
amounts.add(Money.of(13.37, "JPY"));
amounts.add(Money.of(18, "USD"));
Custom MonetaryAmount operations
// A monetary operator that returns 10% of the input MonetaryAmount
// Implemented using Java 8 Lambdas
MonetaryOperator tenPercentOperator = (MonetaryAmount amount) -> {
BigDecimal baseAmount = amount.getNumber().numberValue(BigDecimal.class);
BigDecimal tenPercent = baseAmount.multiply(new BigDecimal("0.1"));
return Money.of(tenPercent, amount.getCurrency());
};
MonetaryAmount dollars = Money.of(12.34567, "USD");
// apply tenPercentOperator to MonetaryAmount
MonetaryAmount tenPercentDollars = dollars.with(tenPercentOperator); // USD 1.234567
Resources:
Handling money and currencies in Java with JSR 354
Looking into the Java 9 Money and Currency API (JSR 354)
See Also: JSR 354 - Currency and Money

- 2,863
- 32
- 41
-
All this is nice, but as Federico suggested above, it looks slower than BigDecimal :-)) bad joke then only, but I will give it test now 1 year later... – kensai Dec 25 '17 at 05:22
I have done a microbenchmark (JMH) to compare Moneta (java currency JSR 354 implementation) against BigDecimal in terms of performance.
Surprisingly, BigDecimal performance seems to be better than moneta's. I have used following moneta config:
org.javamoney.moneta.Money.defaults.precision=19 org.javamoney.moneta.Money.defaults.roundingMode=HALF_UP
package com.despegar.bookedia.money;
import org.javamoney.moneta.FastMoney;
import org.javamoney.moneta.Money;
import org.openjdk.jmh.annotations.*;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.concurrent.TimeUnit;
@Measurement(batchSize = 5000, iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS)
@Warmup(iterations = 2)
@Threads(value = 1)
@Fork(value = 1)
@State(Scope.Benchmark)
@BenchmarkMode(Mode.Throughput)
public class BigDecimalBenchmark {
private static final Money MONEY_BASE = Money.of(1234567.3444, "EUR");
private static final Money MONEY_SUBSTRACT = Money.of(232323, "EUR");
private static final FastMoney FAST_MONEY_SUBSTRACT = FastMoney.of(232323, "EUR");
private static final FastMoney FAST_MONEY_BASE = FastMoney.of(1234567.3444, "EUR");
MathContext mc = new MathContext(10, RoundingMode.HALF_UP);
@Benchmark
public void bigdecimal_string() {
new BigDecimal("1234567.3444").subtract(new BigDecimal("232323")).multiply(new BigDecimal("3.4"), mc).divide(new BigDecimal("5.456"), mc);
}
@Benchmark
public void bigdecimal_valueOf() {
BigDecimal.valueOf(12345673444L, 4).subtract(BigDecimal.valueOf(232323L)).multiply(BigDecimal.valueOf(34, 1), mc).divide(BigDecimal.valueOf(5456, 3), mc);
}
@Benchmark
public void fastmoney() {
FastMoney.of(1234567.3444, "EUR").subtract(FastMoney.of(232323, "EUR")).multiply(3.4).divide(5.456);
}
@Benchmark
public void money() {
Money.of(1234567.3444, "EUR").subtract(Money.of(232323, "EUR")).multiply(3.4).divide(5.456);
}
@Benchmark
public void money_static(){
MONEY_BASE.subtract(MONEY_SUBSTRACT).multiply(3.4).divide(5.456);
}
@Benchmark
public void fastmoney_static() {
FAST_MONEY_BASE.subtract(FAST_MONEY_SUBSTRACT).multiply(3.4).divide(5.456);
}
}
Resulting in
Benchmark Mode Cnt Score Error Units
BigDecimalBenchmark.bigdecimal_string thrpt 10 479.465 ± 26.821 ops/s
BigDecimalBenchmark.bigdecimal_valueOf thrpt 10 1066.754 ± 40.997 ops/s
BigDecimalBenchmark.fastmoney thrpt 10 83.917 ± 4.612 ops/s
BigDecimalBenchmark.fastmoney_static thrpt 10 504.676 ± 21.642 ops/s
BigDecimalBenchmark.money thrpt 10 59.897 ± 3.061 ops/s
BigDecimalBenchmark.money_static thrpt 10 184.767 ± 7.017 ops/s
Please feel free to correct me if i'm missing something

- 499
- 1
- 5
- 11
You should use BigDecimal to represent monetary values .It allows you to use a variety of rounding modes, and in financial applications, the rounding mode is often a hard requirement that may even be mandated by law.

- 10,567
- 8
- 45
- 57
For simple case (one currency) it'is enough int
/long
.
Keep money in cents (...) or hundredth / thousandth of cents (any precision you need with fixed divider)

- 16,647
- 10
- 125
- 197
I would use Joda Money
It's still at version 0.6 but looks very promising

- 60,927
- 15
- 95
- 117

- 23,584
- 10
- 62
- 58
BigDecimal is the best data type to use for currency.
There are a whole lot of containers for currency, but they all use BigDecimal as the underlying data type. You won't go wrong with BigDecimal, probably using BigDecimal.ROUND_HALF_EVEN rounding.

- 5,328
- 2
- 25
- 24
I like using Tiny Types which would wrap either a double, BigDecimal, or int as previous answers have suggested. (I would use a double unless precision problems crop up).
A Tiny Type gives you type safety so you don't confused a double money with other doubles.

- 688
- 1
- 7
- 24
-
6While I too like tiny types, you should *Never* use a double to store a monetary value. – orien Nov 16 '11 at 12:23