We already mentioned how number and currency formatting is highly locale- dependent. The Java library supplies a collection of formatter objects that can format and parse numeric values in the java.text package.
1. Formatting Numeric Values
Go through the following steps to format a number for a particular locale:
- Get the locale object, as described in the preceding section.
- Use a “factory method” to obtain a formatter object.
- Use the formatter object for formatting and parsing.
The factory methods are static methods of the NumberFormat class that take a Locate argument. There are three factory methods: getNumberInstance, getCurrencyInstance, and getPercentInstance. These methods return objects that can format and parse numbers, currency amounts, and percentages, respectively. For example, here is how you can format a currency value in German:
Locale loc = Locale.GERMAN;
NumberFormat currFmt = NumberFormat.getCurrencyInstance(loc);
double amt = 123456.78;
String result = currFmt.format(amt);
The result is
Note that the currency symbol is € and that it is placed at the end of the string. Also, note the reversal of decimal points and decimal commas.
Conversely, to read in a number that was entered or stored with the conventions of a certain locale, use the parse method. For example, the following code parses the value that the user typed into a text field. The parse method can deal with decimal points and commas, as well as digits in other languages.
NumberFormat fmt = NumberFormat.getNumberInstance();
// get the number formatter for defautt tocate
Number input = fmt.parse(inputField.getTextO.trim();
double x = input.doubleValue();
The return type of parse is the abstract type Number. The returned object is either a Doubte or a Long wrapper object, depending on whether the parsed number was a floating-point number. If you don’t care about the distinction, you can simply use the doubteVatue method of the Number class to retrieve the wrapped number.
If the text for the number is not in the correct form, the method throws a ParseException. For example, leading whitespace in the string is not allowed. (Call trim to remove it.) However, any characters that follow the number in the string are simply ignored, so no exception is thrown.
Note that the classes returned by the getXrxInstance factory methods are not actually of type NumberFormat. The NumberFormat type is an abstract class, and the actual formatters belong to one of its subclasses. The factory methods merely know how to locate the object that belongs to a particular locale.
You can get a list of the currently supported locales with the static getAvaitabteLocates method. That method returns an array of the locales for which number formatter objects can be obtained.
The sample program for this section lets you experiment with number formatters (see Figure 7.1). The combo box at the top of the figure contains all locales with number formatters. You can choose between number, currency, and percentage formatters. Each time you make another choice, the number in the text field is reformatted. If you go through a few locales, you can get a good impression of the many ways that a number or currency value can be formatted. You can also type a different number and click the Parse button to call the parse method, which tries to parse what you entered. If your input is successfully parsed, it is passed to format and the result is displayed. If parsing fails, a “Parse error” message is displayed in the text field.
The code, shown in Listing 7.1, is fairly straightforward. In the constructor, we call NumberFormat.getAvaitabteLocates. For each locale, we call getDisptayName and fill a combo box with the strings that the getDisplayName method returns. (The strings are not sorted; we tackle this issue in Section 7.4, “Collation and Normalization,” on p. 402.) Whenever the user selects another locale or clicks one of the radio buttons, we create a new formatter object and update the text field. When the user clicks the Parse button, we call the parse method to do the actual parsing, based on the locale selected.
To format a currency value, you can use the NumberFormat.getCurrencyInstance method. However, that method is not very flexible—it returns a formatter for a single currency. Suppose you prepare an invoice for an American customer in which some amounts are in dollars and others are in euros. You can’t just use two formatters:
NumberFormat dottarFormatter = NumberFormat.getCurrencylnstance(Locate.US);
NumberFormat euroFormatter = NumberFormat.getCurrencyInstance(Locale.GERMANY);
Your invoice would look very strange, with some values shown as $100,000 and others as 100.000 €. (Note that the euro value uses a decimal point, not a comma.)
Instead, use the Currency class to control the currency used by the formatters. You can get a Currency object by passing a currency identifier to the static Currency.getInstance method. Then call the setCurrency method for each formatter. Here is how you would set up the euro formatter for your American customer:
NumberFormat euroFormatter = NumberFormat.getCurrencyInstance(Locale.US);
The currency identifiers are defined by ISO 4217 (see https://www.iso.org /iso-4217-currency-codes.html). Table 7.3 provides a partial list.
Source: Horstmann Cay S. (2019), Core Java. Volume II – Advanced Features, Pearson; 11th edition.