For a long time, Java didn't have a satisfactory way to represent money. Early versions exhibited issues with currency, precision, rounding, and formatting, and subsequent versions only partially improved these issues. Now, however, we have the best Java specification for handling money to date: JSR 354.
Java Money: A History
In early Java versions, we had to use float and double to work with money, and it was hard to deal with the money's currency, precision (see IEEE-754), rounding, and formatting. Then the BigDecimal and DecimalFormat entered the scene. These helped improve precision and made formatting slightly easier, but there were still issues. At last, in Java 1.4, Currency class was released to improve money formatting.
Nevertheless, users still encountered problems like having to create a couple of objects to deal with money amounts, not having a proper way to deal with currency conversions, not having support for new currencies (like crypto coins), and having difficulties formatting money amounts to different regions.
This is the context in which JSR 354, the Java specification for handling money, was introduced. While the first release of this JSR was early in 2015, the current version is 1.0.3 and resolves the above-mentioned issues. In today's blog, we'll take a closer look at JSR 354's capabilities.
Before we do so, it's important to note that the JSR 354 specification is written for Java SE but can also be used in Java ME and Java EE. The reference implementation was written to work with Java 8, but there's a backport version available to Java 7.
Java Money - Dependencies
Since the JSR 354 is still not released in Java ME or EE, we need to include two libraries: the JSR 354 API and an implementation of this API. (If you want, of course, you can make your own implementation.) In this snippet, I'll use the Moneta implementation. (See the references section at the end of this snippet for important links.)
<dependency> <groupId>javax.money</groupId> <artifactId>money-api</artifactId> <version>1.0.3</version> </dependency> <dependency> <groupId>org.javamoney</groupId> <artifactId>moneta</artifactId> <version>1.2.1</version> </dependency>
compile group: 'javax.money', name: 'money-api', version: '1.0.3' compile group: 'org.javamoney', name: 'moneta', version: '1.2.1'
This API adds a lot of classes, interfaces, utility classes, and builders (builders are very popular today). In this snippet, we'll review its main features. I've also provided an example in the references section showing a simple usage of the JSR 354.
The main class of this API is the Monetary class. From this class we can reach currencies, rounding, and some factories.
We have two main ways to get the CurrencyUnit:
There's a CurrencyQueryBuilder to find the currency that you want:
There's also some important information inside the CurrencyUnit like the currency code and the number of fractal digits shown here:
The MonetaryAmount is the object that joins the money value with the CurrencyUnit. In the code below, we have two examples:
The main differences between Money.of and FastMoney.of relate to precision and performance. Money.of has a a precision of 256 digits while FastMoney has a precision of 19 digits.
Of course, we can also get just the currency of the MonetaryAmount or just the number (the value):
With the NumberValue object, we can access some helpful methods, such as getting the amount doubled:
Getting just the fractional part:
Or just the non-fractional part:
We can use the MonetaryQueries to do operations with money:
Finally, we also have a builder to set parameters like the precision of the MonetaryAmount object:
Another important tool to have access to when we work with money is rounding. When we use Math.round, Math.ceil, or Math.floor for float and double values, the fractional value is removed; the rounding must work with the number of fractional numbers in that specific currency (for instance, currencies like LYD, KWD, BHD and CLF have more than 2 fractional digits). Let's look at an example:
We can also use builders. Let's look at how to do that:
One of the most amazing features of this API is its ability to convert between currencies.
To start, the API uses a provider to get the exchange rate. (The providers use the internet to get the current values, but you can also write your own provider that uses offline resources.)
Let's look at this simple example of money conversion:
The default exchange provider is the European Central Bank. When you run this piece of code, you can check some messages about reading the rates. The Moneta implementation comes with some other providers as well; you can change the provider as follows:
Formatting and Parsing
Formatting entails more than just setting the currency code and the value, because some countries use "," and others use "." to separate fractional digits. There's a difference between the disposal order of currency and value, as seen in the following example:
Here is the Builder for that:
You can parse a String directly to the MoneyAmount, but you need to set which format the String is using, as shown below:
The JSR 354 is a very flexible and extensible way to handle money. These days, applications reach a huge number of countries. With this JSR, we can offer our users a better experience when they visualize money values (in terms of conversion and formatting), and JSR's ability to handle new currencies like crypto coins is another great asset.
Below, you'll find a link to a project in my GitHub. In this project, I created a very simple REST application to show some of the operations that I mentioned in this snippet along with an implementation of a new currency as well its own conversion handler.
Jonathan Ohara is a Java Engineer at Avenue Code.