Skip to content

Lesson 02 · Formatting & Parsing

Objectives

After this lesson you will be able to:

  • Format and parse numbers and currency with NumberFormat.
  • Format dates/times for a Locale with a localized DateTimeFormatter.
  • Build parameterized messages with MessageFormat.

NumberFormat

NumberFormat formats numbers, currency, and percentages for a Locale.

java
NumberFormat n = NumberFormat.getInstance(Locale.US);
n.format(1_234.5);                       // "1,234.5"
NumberFormat c = NumberFormat.getCurrencyInstance(Locale.US);
c.format(1234.5);                        // "$1,234.50"
NumberFormat p = NumberFormat.getPercentInstance(Locale.US);
p.format(0.25);                          // "25%"

Formatting and parsing are inverses; parse returns a Number and may throw ParseException:

java
Number parsed = NumberFormat.getInstance(Locale.US).parse("1,234.5");   // 1234.5

Exam trap

NumberFormat.parse returns a Number (could be Long or Double) and throws the checkedjava.text.ParseException — not NumberFormatException. It also stops at the first unparseable character rather than failing (e.g. parse("12abc") returns 12).

Localized date/time formatting

Use a DateTimeFormatter with a locale and a FormatStyle:

java
DateTimeFormatter f = DateTimeFormatter
        .ofLocalizedDate(FormatStyle.MEDIUM)
        .withLocale(Locale.US);
LocalDate.of(2026, 6, 19).format(f);     // "Jun 19, 2026"

The same instant renders differently per locale — FormatStyle.FULL/LONG/MEDIUM/SHORT control verbosity.

MessageFormat

MessageFormat builds messages with positional placeholders {0}, {1}, with optional type/ style ({0,number,currency}, {1,date,short}):

java
String msg = MessageFormat.format(
        "{0} has {1} new messages.", "Alice", 3);     // "Alice has 3 new messages."

Gotcha

MessageFormat placeholders are zero-indexed and reusable. A literal single quote must be doubled (''), and { inside text must be quoted ('{') — a lone quote suppresses formatting of the following segment.

SDET note

When asserting localized output, pin the Locale explicitly (getInstance(Locale.US)) — never rely on the JVM default, which varies by machine and makes tests non-portable. Better still, assert a parse round-trip (format then parse) so CLDR data changes don't break the test on a wording tweak.

Key Takeaways

  • NumberFormat (getInstance/getCurrencyInstance/getPercentInstance) formats and parses for a Locale. parse returns a Number, throws checked ParseException, and stops at the first bad char.
  • Localize dates with DateTimeFormatter.ofLocalizedDate(style).withLocale(...) and a FormatStyle.
  • MessageFormat uses zero-indexed {0} placeholders (with optional ,number,/,date, types); double literal quotes.
  • Always pin the Locale in tests; the JVM default is not portable.

Lesson Quiz

Lesson Quiz · Formatting & Parsing0 / 5
  1. What does NumberFormat.getCurrencyInstance(Locale.US).format(1234.5) produce?

    • A"1234.5"
    • B"$1,234.50"
    • C"USD 1234.5"
    • D"$1234.5"
  2. What exception does NumberFormat.parse throw on bad input?

    • ANumberFormatException
    • BParseException (checked)
    • CIllegalArgumentException
    • DNone
  3. What does NumberFormat.getInstance(Locale.US).parse("12abc") return?

    • ANumberFormatException
    • B12
    • C0
    • Dnull
  4. MessageFormat placeholders are...

    • A1-indexed {1}
    • B0-indexed {0}
    • Cnamed ${x}
    • D%s style
  5. In a test, why pin the Locale explicitly?

    • AIt's faster
    • BThe JVM default Locale varies by machine, making output non-portable
    • CRequired by the compiler
    • DTo avoid ParseException

Next: Module 09 Mini-Exam. Run the matching code in labs/src/main/java/com/jse21/m09_localization/.