I just announced the new Spring 5 modules in REST With Spring:

>> CHECK OUT THE COURSE

1. Overview

In this tutorial, we’ll see how we can convert a monetary amount into words-representation in Java.

We’ll also see how a custom implementation could look like, via an external library – Tradukisto.

2. Implementation

Let’s first start with our own implementation. The first step is to declare two String arrays with the following elements:

public static String[] ones = { 
  "", "one", "two", "three", "four", 
  "five", "six", "seven", "eight", 
  "nine", "ten", "eleven", "twelve", 
  "thirteen", "fourteen", "fifteen", 
  "sixteen", "seventeen", "eighteen", 
  "nineteen" 
};

public static String[] tens = {
  "",          // 0
  "",          // 1
  "twenty",    // 2
  "thirty",    // 3
  "forty",     // 4
  "fifty",     // 5
  "sixty",     // 6
  "seventy",   // 7
  "eighty",    // 8
  "ninety"     // 9
};

When we receive an input, we’ll need to handle the invalid values (zero and negative values). Once a valid input is received, we can extract the number of dollars and cents into variables:

 long dollars = (long) money;
 long cents = Math.round((money - dollars) * 100);

If the number given is less than 20, then we’ll get the appropriate ones’ element from the array based on the index:

if (n < 20) {
    return ones[(int) n];
}

We’ll use a similar approach for numbers less than 100, but now we have to use tens array as well:

if (n < 100) {
    return tens[(int) n / 10] 
      + ((n % 10 != 0) ? " " : "") 
      + ones[(int) n % 10];
}

We do this similarly for numbers that are less than one thousand.

Next, we use recursive calls to deal with numbers that are less than one million, as shown below:

if (n < 1_000_000) {
    return convert(n / 1000) + " thousand" + ((n % 1000 != 0) ? " " : "") 
      + convert(n % 1000);
}

The same approach is used for numbers that are less than one billion, and so on.

Here is the main method that can be called to do this conversion:

 public static String getMoneyIntoWords(double money) {
    long dollars = (long) money;
    long cents = Math.round((money - dollars) * 100);
    if (money == 0D) {
        return "";
    }
    if (money < 0) {
        return INVALID_INPUT_GIVEN;
    }
    String dollarsPart = "";
    if (dollars > 0) {
        dollarsPart = convert(dollars) 
          + " dollar" 
          + (dollars == 1 ? "" : "s");
    }
    String centsPart = "";
    if (cents > 0) {
        if (dollarParts.length() > 0) {
            centsPart = " and ";
        }
        centsPart += convert(cents) + " cent" + (cents == 1 ? "" : "s");
    }
    return dollarsPart + centsPart;
}

Let’s test our code to make sure it works:

@Test
public void whenGivenDollarsAndCents_thenReturnWords() {
    String expectedResult
     = "nine hundred twenty four dollars and sixty cents";
    
    assertEquals(
      expectedResult, 
      NumberWordConverter.getMoneyIntoWords(924.6));
}

@Test
public void whenTwoBillionDollarsGiven_thenReturnWords() {
    String expectedResult 
      = "two billion one hundred thirty three million two hundred" 
        + " forty seven thousand eight hundred ten dollars";
 
    assertEquals(
      expectedResult, 
      NumberWordConverter.getMoneyIntoWords(2_133_247_810));
}

@Test
public void whenThirtyMillionDollarsGiven_thenReturnWords() {
    String expectedResult 
      = "thirty three million three hundred forty eight thousand nine hundred seventy eight dollars";
    assertEquals(
      expectedResult, 
      NumberWordConverter.getMoneyIntoWords(33_348_978));
}

Let’s also test some edge cases, and make sure we have covered them as well:

@Test
public void whenZeroDollarsGiven_thenReturnEmptyString() {
    assertEquals("", NumberWordConverter.getMoneyIntoWords(0));
}

@Test
public void whenNoDollarsAndNineFiveNineCents_thenCorrectRounding() {
    assertEquals(   
      "ninety six cents", 
      NumberWordConverter.getMoneyIntoWords(0.959));
}
  
@Test
public void whenNoDollarsAndOneCent_thenReturnCentSingular() {
    assertEquals(
      "one cent", 
      NumberWordConverter.getMoneyIntoWords(0.01));
}

3. Using a Library

Now that we’ve implemented our own algorithm, let’s do this conversion by using an existing library.

Tradukisto is a library for Java 8+, which can help us convert numbers to their word representations. First, we need to import it into our project (the latest version of this library can be found here):

<dependency>
    <groupId>pl.allegro.finance</groupId>
    <artifactId>tradukisto</artifactId>
    <version>1.0.1</version>
</dependency>

We can now use MoneyConverters‘s asWords() method to do this conversion:

public String getMoneyIntoWords(String input) {
    MoneyConverters converter = MoneyConverters.ENGLISH_BANKING_MONEY_VALUE;
    return converter.asWords(new BigDecimal(input));
}

Let’s test this method with a simple test case:

@Test
public void whenGivenDollarsAndCents_thenReturnWordsVersionTwo() {
    assertEquals(
      "three hundred ten £ 00/100", 
      NumberWordConverter.getMoneyIntoWords("310"));
}

We could also use the ICU4J library to do this, but it’s a large one and comes with many other features that are out of the scope of this article.

However, have a look at it if Unicode and globalization support is needed.

4. Conclusion

In this quick article, we saw two approaches on how to do the conversion of a sum of money into words.

The code for all the examples explained here, and much more can be found over on GitHub.

I just announced the new Spring 5 modules in REST With Spring:

>> CHECK OUT THE LESSONS

Leave a Reply

2 Comments on "Displaying Money Amounts in Words"

avatar
  Subscribe  
newest oldest most voted
Notify of
Rett
Guest

And what about localisation? Are there ready libraries?

Loredana Crusoveanu
Editor

The tradukisto library supports several languages: https://github.com/allegro/tradukisto

ICU4J is another library with support for internalization, but I haven’t looked too in depth into it.