Number Formatting

Figure 535. Excerpt from java.util.Locale Slide presentation

A Locale object represents a specific geographical, political, or cultural region.

An operation that requires a Locale to perform its task is called locale-sensitive and uses the Locale to tailor information for the user.

For example, displaying a number is a locale-sensitive operation: Numbers should be formatted according to the customs and conventions of the user's native country, region, or culture.


Figure 536. Locale properties Slide presentation
  • Language

  • Encoding

  • Country

  • Extensible


Figure 537. Get a NumberFormat instance Slide presentation
final NumberFormat standard = new DecimalFormat();
System.out.println(standard.format(1234.5678));

final NumberFormat de =
    DecimalFormat.getInstance(Locale.GERMANY);
System.out.println(de.format(1234.5678));
1234.5678
1.234,568

Figure 538. Create a custom formatter Slide presentation
final DecimalFormatSymbols unusualSymbols =
  new DecimalFormatSymbols(Locale.getDefault());
unusualSymbols.setDecimalSeparator('|');
unusualSymbols.setGroupingSeparator('^');

final String strange = "#,##0.###";
final DecimalFormat weirdFormatter = new DecimalFormat(strange, unusualSymbols);
weirdFormatter.setGroupingSize(4);

System.out.println(weirdFormatter.format(12345.678));
1^2345|678

exercise No. 176

Locale definitions

Q:

Each JRE ships with a set of available Locale definitions. Write a simple program to get the following list:

160 locales available:
Locale: Arabic(ar_AE)
Locale: Arabic(ar_JO)
Locale: Arabic(ar_SY)
Locale: Croatian(hr_HR)
...
Locale: Indonesian(in_ID)
Locale: English(en_GB)

Tip

Read the documentation of Locale to find appropriate methods.

A:

System.out.println(Locale.getAvailableLocales().length + " locales available:");
for (final Locale l: Locale.getAvailableLocales()) {
  System.out.println("Locale: " + l.getDisplayLanguage() + "(" + l + ")");
}

exercise No. 177

Formatting int, double and LocaleDate

Q:

Implement the following three overloaded class methods:

/**
 * Print an int value using the given locale. Example:
 *
 * Using Locale.GERMANY a value of 1234567 should appear as "1.234.567"
 *
 * @param value The value to be formatted.
 * @param locale The locale to be used.
 */
static public void print(final int value,  final Locale locale) {...}
/**
 * Print a double value using the given locale. Example:
 *
 * Using Locale.GERMANY a value of -123.456789 should appear as "-123,457"
 *
 * @param value The value to be formatted.
 * @param locale The locale to be used.
 */
static public void print(final double value,  final Locale locale) {...}
/**
 * Print a {@link LocalDate} value using the given locale. Example:
 *
 * Using Locale.GERMANY the 22-nd of december 2024 should appear as "22. Dezember 2024".
 *
 * @param value The value to be formatted.
 * @param locale The locale to be used.
 */
static public void print(final LocalDate date,  final Locale locale) {...}

You may use them as:

for (final Locale locale : new Locale[]{Locale.GERMANY, Locale.JAPAN, Locale.US}) {
  System.out.println("Locale " + locale.getDisplayCountry());
  print(1234567, locale);
  print(-123.456789, locale);
  print(LocalDate.of(2024, Month.DECEMBER, 22), locale);
  System.out.println("----------------------\n");
}

The expected output reads:

Locale Germany
1.234.567
-123,457
22. Dezember 2024
----------------------

Locale Japan
1,234,567
-123.457
2024/12/22
----------------------

Locale United States
1,234,567
-123.457
December 22, 2024
----------------------

Tip

A:

Implementing the first two methods is relatively simple:

/**
 * Print an int value using the given locale. Example:
 *
 * Using Locale.GERMANY a value of 1234567 should appear as "1.234.567"
 *
 * @param value The value to be formatted.
 * @param locale The locale to be used.
 */
static public void print(final int value,  final Locale locale) {
  final NumberFormat numberFormat = NumberFormat.getInstance(locale);
  System.out.println(numberFormat.format(value));
}
/**
 * Print a double value using the given locale. Example:
 *
 * Using Locale.GERMANY a value of -123.456789 should appear as "-123,457"
 *
 * @param value The value to be formatted.
 * @param locale The locale to be used.
 */
static public void print(final double value,  final Locale locale) {
  final NumberFormat numberFormat = NumberFormat.getInstance(locale);
  System.out.println(numberFormat.format(value));
}

Processing dates is a bit cumbersome:

/**
 * Print a {@link LocalDate} value using the given locale. Example:
 *
 * Using Locale.GERMANY the 22-nd of december 2024 should appear as "22. Dezember 2024".
 *
 * @param value The value to be formatted.
 * @param locale The locale to be used.
 */
static public void print(final LocalDate date,  final Locale locale) {
  final DateTimeFormatter dateFormat =
    DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).withLocale(locale);
  System.out.println(dateFormat.format(date));
}
Figure 539. Polymorphic number parsing Slide presentation
final NumberFormat de = NumberFormat.getInstance(Locale.GERMANY),
                       us = NumberFormat.getInstance(Locale.US);
try {
  final Number[] values = {
    de.parse("103.234"), de.parse("400.000,234"),
    us.parse("103.234"), us.parse("400.000,234"),};
  for (final Number n: values) {
    System.out.println(n + "(" + n.getClass().getTypeName() + ")");
  } catch (ParseException e) { ... }
103234(java.lang.Long)
400000.234(java.lang.Double)
103.234(java.lang.Double)
400(java.lang.Long)