Java is very often used to develop big financial systems, yet still the JDK has little or no support for monetary arithmetics, currency conversion, formatting money for different locales etc. There’s only a Currency class which serves as a list of ISO 4217 currencies.

Fortunately we’ve got the JSR-354 standard and Moneta – the reference implementation. It provides us the Martin Fowler’s money pattern along with string formatting and currency repositories.

In this article I will focus on displaying monetary amounts for different currencies, locales and personal preferences.

Basic example: amount and ISO symbol

final Locale[] locales = {
    Locale.US,
    new Locale("nl", "NL"),
    new Locale("pl", "PL")
};

final Money amount = Money.of(12345.67, "USD");

for (Locale locale : locales) {
  MonetaryAmountFormat formatter = MonetaryFormats.getAmountFormat(locale);
  System.out.println(formatter.format(amount));
}
en_US nl_NL pl_PL
USD12,345.67 USD 12.345,67 12 345,67 USD

Amount with a currency symbol

final Locale[] locales = {
    Locale.US,
    new Locale("nl", "NL"),
    new Locale("pl", "PL")
};

final Money amount = Money.of(12345.67, "USD");

for (Locale locale : locales) {
  MonetaryAmountFormat formatter = MonetaryFormats.getAmountFormat(
      AmountFormatQueryBuilder.of(locale)
          .set(CurrencyStyle.SYMBOL)
          .build());
  System.out.println(formatter.format(amount));
}
en_US nl_NL pl_PL
$12,345.67 USD 12.345,67 12 345,67 USD

The $ currency symbol is displayed only for the United States locale. Other languages do not use it.

Amount with a full currency name

final Locale[] locales = {
    Locale.US,
    new Locale("nl", "NL"),
    new Locale("pl", "PL")
};

final Money amount = Money.of(12345.67, "USD");

for (Locale locale : locales) {
  MonetaryAmountFormat formatter = MonetaryFormats.getAmountFormat(
      AmountFormatQueryBuilder.of(locale)
          .set(CurrencyStyle.NAME)
          .build());
  System.out.println(formatter.format(amount));
}
en_US nl_NL pl_PL
US Dollar12,345.67 US Dollar 12.345,67 12 345,67 US Dollar

Amount without a thousands separator

final Locale[] locales = {
    Locale.US,
    new Locale("nl", "NL"),
    new Locale("pl", "PL")
};

final Money amount = Money.of(12345.67, "USD");

for (Locale locale : locales) {
  MonetaryAmountFormat formatter = MonetaryFormats.getAmountFormat(
      AmountFormatQueryBuilder.of(locale)
          .set(AmountFormatParams.GROUPING_SIZES, new int[]{2, 0})
          .build());
  System.out.println(formatter.format(amount));
}
en_US nl_NL pl_PL
USD12345.67 USD 12345,67 12345,67 USD

Grouping sizes are specified starting from the decimal point. In the above example we have two digits after the decimal point, and then we have no more grouping going to the left. Of course other combinations are possible, e.g. {2, 3, 4}.

Custom pattern

Using a pattern as defined by java.text.DecimalFormat.

final Locale[] locales = {
    Locale.US,
    new Locale("nl", "NL"),
    new Locale("pl", "PL")
};
final Money amount = Money.of(12345.67, "USD");
for (Locale locale : locales) {
  MonetaryAmountFormat formatter = MonetaryFormats.getAmountFormat(
      AmountFormatQueryBuilder.of(locale)
          .set(AmountFormatParams.PATTERN, "###,###.## ¤")
          .build());
  System.out.println(formatter.format(amount));
}
en_US nl_NL pl_PL
12,345.67 USD 12.345,67 USD 12 345,67 USD