Logo Icon Logo
A Crowd-sourced Cookbook on Writing Great Android® Apps
GitHub logo Twitter logo OReilly Book Cover Art

Formatting Numbers

Author: Ian Darwin -- Published? true -- FormatLanguage: W

Problem:

You need to format numbers, because the default formatting of Double.toString() and friends do not give you enough control over how the results are displayed.

Solution:

Use String.format() or one of the NumberFormat subclasses.

Discussion:

The printf() function was included in the C programming language in the 1970's, and used in many other languages since, including Java. Here's a simple printf example in Java SE:

System.out.printf("Hello %s at %s%n", userName, time);

This could be expected to print something like

Hello Robin at Wed Jun 16 08:38:46 EDT 2010

Since we don't use System.out in Android, you'll be relieved to note that you can get the same String that would be printed, for putting it into a View, by using:

String msg = String.format("Hello %s at %s%n", userName, time);

If you haven't seen printf before, the first argument is obviously the format code string, and all the other arguments (userName and time) are values to be formatted. The format codes begin with a percent sign ('%') and have at least one "type" code; common type codes are shown in the table.

Some common format codes
Character Meaning s String (convert primitive values using defaults; convert objects by toString)
d Decimal integer (int, long)
f Floating point (float, double)
n Newline
t Time/Date formats, Java-specific; see below

The default date formatting is pretty ugly, so we often need to expand on it. The printf formatting capabilities are actually housed in the java.util.Formatter class, to which reference should be made for the full details of its formatting language.

Unlike printf in other languages you may have used, all these format routines optionally allow you to refer to arguments by their number, by putting a number plus a dollar sign after the '%' lead-in but before the formatting code proper, for example "%2$3.1f" means to format the second argument as a decimal number with three characters and one digit after the decimal place. This numbering can be used for two purposes: to change the order in which arguments print (often useful with internationalization), and to refer to a given argument more than once. The date/time format character 't' requires a second character after it, such as Y for the year, 'm' for month, and so on. Here we take the time argument and extract several fields from it:

msg = String.format("Hello at %1$tB %1$td, %1$tY%n", time);

This might format as July 4, 2010.

To print numbers with a specific precision, you can use 'f' with a width and a precision, such as

msg = String.format("Latitude: %10.6f", latitude);

This might yield:

Latitude: -79.281818

While such formatting is OK for specific uses such as latitudes and longitudes, for general use such as currencies, it may give you too much control.

General Formatters

Java has an entire package, java.text, full of formatting routines as general and flexible as anything you might imagine. As with printf, it has an involved formatting language, described in the online documentation page. Consider the presentation of numbers. In North America, the number "one thousand twenty-four and a quarter" is written 1,024.25, in most of Europe it is 1 024,25, and in some other part of the world it might be written 1.024,25. Not to mention how currencies and percentages are formatted! Trying to keep track of this yourself would drive the average small software developer around the bend rather quickly.

Fortunately, the java.text package includes a Locale class, and, furthermore, the Java or Android runtime automatically sets a default Locale object based on the user's environment; this code works the same on desktop Java as it does in Android. To provide formatters customized for numbers, currencies, and percentages, the NumberFormat class has static factory methods that normally return a DecimalFormat with the correct pattern already instantiated. A DecimalFormat object appropriate to the user's locale can be obtained from the factory method NumberFormat.getInstance() and manipulated using set methods. Surprisingly, the method setMinimumIntegerDigits() turns out to be the easy way to generate a number format with leading zeros. Here is an example:

import java.text.NumberFormat;

/*
 * Format a number our way and the default way.
 */
public class NumFormat2 {
	/** A number to format */
	public static final double data[] = {
		0, 1, 22d/7, 100.2345678
	};

	public static void main(String[] av) { 
		// Get a format instance
		NumberFormat form = NumberFormat.getInstance();

		// Tailor it to look like 999.99[99]
		form.setMinimumIntegerDigits(3);
		form.setMinimumFractionDigits(2);
		form.setMaximumFractionDigits(4);

		// Now print using it.
		for (int i=0; i<data.length; i++)
			System.out.println(data[i] + "\tformats as " +
				form.format(data[i]));
	}
}

This prints the contents of the array using the NumberFormat instance form. We show running it as a main program instead of in an Android application just to isolate the effects of the NumberFormat.

$ java NumFormat2 0.0 formats as 000.00 1.0 formats as 001.00 3.142857142857143 formats as 003.1429 100.2345678 formats as 100.2346

You can also construct a DecimalFormat with a particular pattern or change the pattern dynamically using applyPattern(). Some of the more common pattern characters are shown in this table.

DecimalFormat pattern characters
Character Explanation
# Numeric digit (leading zeros suppressed)
0 Numeric digit (leading zeros provided)
. Locale-specific decimal separator (decimal point)
, Locale-specific grouping separator (comma in English)
- Locale-specific negative indicator (minus sign)
% Shows the value as a percentage
; Separates two formats: the first for positive and the second for negative values
' Escapes one of the above characters so it appears as itself
Anything else Appears as itself

The NumFormatTest program uses one DecimalFormat to print a number with only two decimal places and a second to format the number according to the default locale:

import java.text.DecimalFormat;
import java.text.NumberFormat;

public class NumFormatTest {
	/** A number to format */
	public static final double intlNumber = 1024.25;
	/** Another number to format */
	public static final double ourNumber = 100.2345678;

	public static void main(String[] av) { 

		NumberFormat defForm = NumberFormat.getInstance();
		NumberFormat ourForm = new DecimalFormat("##0.##");
		// toPattern() will reveal the combination of #0., etc
		// that this particular Locale uses to format with
		System.out.println("defForm's pattern is " +
			((DecimalFormat)defForm).toPattern());
		System.out.println(intlNumber + " formats as " +
			defForm.format(intlNumber));
		System.out.println(ourNumber + " formats as " +
			ourForm.format(ourNumber));
		System.out.println(ourNumber + " formats as " +
			defForm.format(ourNumber) + " using the default format");
	}
}

This program prints the given pattern and then formats the same number using several formats:

$ java NumFormatTest
defForm's pattern is #,##0.###
1024.25 formats as 1,024.25
100.2345678 formats as 100.23
100.2345678 formats as 100.235 using the default format

See Also:

Chapter Ten of the Java Cookbook; Part VI of Java I/O by Elliotte Rusty Harold.

No records found.