Java Cookbook, Second Edition

Problem

You need to format numbers.

Solution

Use a NumberFormat subclass.

Java has not traditionally provided a C-style printf /scanf functions because they tend to mix together formatting and input/output in a very inflexible way. Programs using printf/scanf can be very hard to internationalize, for example.

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 Javadoc page. Consider the presentation of long 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 shop around the bend rather quickly.

Fortunately, the java.text package includes a Locale class, and, furthermore, the Java runtime automatically sets a default Locale object based on the user's environment; e.g., on the Macintosh and Windows, the user's preferences; on Unix, the user's environment variables. (To provide a nondefault locale, see Recipe 15.8.) 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.*; import java.util.*; /* * 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 }; /** The main (and only) method in this class. */ public static void main(String av[]) { // Get a format instance NumberFormat form = NumberFormat.getInstance( ); // Set 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:

$ 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 Table 5-2.

Table 5-2. DecimalFormat pattern characters

Character

Meaning

#

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

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:

// NumFormatTest.java /** A number to format */ public static final double intlNumber = 1024.25; /** Another number to format */ public static final double ourNumber = 100.2345678; NumberFormat defForm = NumberFormat.getInstance( ); NumberFormat ourForm = new DecimalFormat("##0.##"); // toPattern( ) shows the combination of #0., etc // that this particular local 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 17; O'Reilly's Java I/O by Elliotte Rusty Harold.

Категории