Appearance
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
Localewith a localizedDateTimeFormatter. - 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.5Exam 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 aLocale.parsereturns aNumber, throws checkedParseException, and stops at the first bad char.- Localize dates with
DateTimeFormatter.ofLocalizedDate(style).withLocale(...)and aFormatStyle. MessageFormatuses zero-indexed{0}placeholders (with optional,number,/,date,types); double literal quotes.- Always pin the
Localein tests; the JVM default is not portable.
Lesson Quiz
What does NumberFormat.getCurrencyInstance(Locale.US).format(1234.5) produce?
What exception does NumberFormat.parse throw on bad input?
What does NumberFormat.getInstance(Locale.US).parse("12abc") return?
MessageFormat placeholders are...
In a test, why pin the Locale explicitly?
Next: Module 09 Mini-Exam. Run the matching code in labs/src/main/java/com/jse21/m09_localization/.