Study guide

11.4 Internationalization and Localization: `Locale`, `ResourceBundle`, and Formatters

Oracle Java SE 17 Developer Certified Professional 1Z0-829

Track your progress as you read

Finished sections get a check mark.

1 Introduction: The 1Z0-829 Exam

About the Java SE 17 Developer (1Z0-829) Exam

2 Chapter 1: Java Fundamentals & Language Basics

1.1 Primitive Types, Literals, Wrapper Classes, and Type Promotion/Casting 1.2 Local Variable Type Inference (`var`) Rules and Scoping 1.3 Operators, Precedence, Evaluation Order, and Short-Circuit Evaluation 1.4 Text Blocks, String Immutability, and StringBuilder APIs

3 Chapter 2: Program Flow & Decision Constructs

2.1 Conditional Branching with if/else and the Ternary Operator 2.2 Switch Statements and Switch Expressions 2.3 Iteration Constructs, Loop Control, and Branching Labels

4 Chapter 3: Object-Oriented Design & Class Mechanics

3.1 Class Declarations, Field/Method Signatures, and Access Modifiers 3.2 Constructors, Overloading, Initialization Order, and Garbage Collection 3.3 Inheritance, Method Overriding, Polymorphism, and `super`/`this` 3.4 Abstract Classes, Static Members, and Object Methods (`equals`, `hashCode`, `toString`)

5 Chapter 4: Advanced OOP: Interfaces, Records & Sealed Types

4.1 Interface Architecture: Default, Static, and Private Methods 4.2 Enumerations: Constants, Constructors, Methods, and Custom Bodies 4.3 Records: Canonical/Compact Constructors, Components, and Immutability 4.4 Sealed Classes and Interfaces: `permits`, Hierarchy Constraints, and Modifiers

6 Chapter 5: Pattern Matching & Nested Types

5.1 Pattern Matching for `instanceof` and Flow Scoping Mechanics 5.2 Nested Types: Member Inner, Static Nested, Local, and Anonymous Classes 5.3 Defensive Programming, Immutability Patterns, and Validation

7 Chapter 6: Generics, Collections & Arrays

6.1 Generic Classes, Interfaces, Methods, and Type Erasure 6.2 Bounded Type Parameters and Wildcards (PECS Rule) 6.3 Collections Framework: List, Set, Queue, and Deque APIs 6.4 The Map Interface, Sorting, Comparable, and Comparator 6.5 Arrays: Declaration, Initialization, Multidimensional Arrays, and the Arrays Utility Class

8 Chapter 7: Functional Programming & Lambda Expressions

7.1 Functional Interfaces and Lambda Syntax Rules 7.2 Standard Functional Interfaces in `java.util.function` 7.3 Method References: Static, Bound, Unbound, and Constructor References

9 Chapter 8: The Stream API

8.1 Stream Lifecycle: Creation, Pipeline Architecture, and Lazy Evaluation 8.2 Intermediate Stream Operations: Filtering, Mapping, Sorting, and Slicing 8.3 Terminal Stream Operations: Reduction, Matching, Finding, and Collecting 8.4 Primitive Streams (`IntStream`, `LongStream`, `DoubleStream`) and Numeric Statistics

10 Chapter 9: Advanced Streams & Collectors

9.1 The Optional Class: Safe Null Handling, Transformation, and Chaining 9.2 The Collectors API: Downstream Reductions, Grouping, and Partitioning 9.3 Parallel Streams: Fork/Join Pool, Spliterators, and Concurrency Pitfalls

11 Chapter 10: Exception Handling

10.1 The Java Exception Hierarchy: Checked vs. Unchecked Exceptions and Errors 10.2 Exception Constructs: `try-catch-finally`, Multi-Catch, and Rethrowing 10.3 Try-With-Resources, `AutoCloseable`, Suppressed Exceptions, and Custom Exceptions

12 Chapter 11: Date/Time API & Localization

11.1 Date and Time Core Types: `LocalDate`, `LocalTime`, `LocalDateTime` 11.2 Timestamps, Intervals, and Durations: `Instant`, `Period`, and `Duration` 11.3 Time Zones, Daylight Saving Time (DST) Offsets, and `ZonedDateTime` 11.4 Internationalization and Localization: `Locale`, `ResourceBundle`, and Formatters 11.5 Formatting and Parsing Messages, Numbers, Percentages, and Localized Dates

13 Chapter 12: Java Platform Module System (JPMS)

12.1 Module Architecture, `module-info.java`, and Module Paths 12.2 Module Directives: `requires`, `requires transitive`, `exports`, and Qualified Exports 12.3 Reflection, Deep Encapsulation, `opens`, and Open Modules 12.4 Services in JPMS (`uses`, `provides...with`), Migration Paths, and Tooling (`jlink`, `jdeps`) 12.5 Compiling and Packaging Code: Non-Modular JARs, Modular JARs, and Migration Strategies

14 Chapter 13: Concurrency & Multithreading

13.1 Thread Fundamentals, `Runnable`, `Callable`, and Thread Lifecycle 13.2 Memory Visibility, `volatile`, Intrinsic Locks, and Synchronization 13.3 The Concurrency Framework: `ExecutorService`, Thread Pools, and `Future` 13.4 Concurrent Collections, Atomic Variables, Explicit Locks, and `CompletableFuture`

15 Chapter 14: Java I/O and NIO.2

14.1 Classical I/O: Byte and Character Streams, Readers, Writers, and Buffering 14.2 Object Serialization, `Serializable`, `transient`, and `serialVersionUID` 14.3 NIO.2 Architecture: `Path`, `Paths`, and Basic `Files` Operations 14.4 Advanced NIO.2: Directory Walking, Streams (`Files.lines`, `walk`), and `WatchService`

16 Chapter 15: Accessing Databases with JDBC

15.1 JDBC Architecture, Drivers, `DriverManager`, and `DataSource` Connections 15.2 SQL Execution: `Statement`, `PreparedStatement`, and `CallableStatement` 15.3 `ResultSet` Navigation, Data Types, and Transaction Management (Commit, Rollback, Savepoints)

17 Chapter 16: Annotations & the Java Logging API

16.1 Standard Annotations: @Override, @FunctionalInterface, @Deprecated, @SuppressWarnings, and @SafeVarargs 16.2 Java Logging API Basics: Logger, Levels, Handlers, and Configuration

11.4 Internationalization and Localization: `Locale`, `ResourceBundle`, and Formatters

Key Takeaways Explain This Topic AI

Locale combines a lowercase language code (ISO 639) with an optional uppercase country code (ISO 3166); Java 17 code builds locales with constants such as Locale.US, new Locale("fr", "CA"), Locale.forLanguageTag(), or Locale.Builder, because Locale.of() arrived only in Java 19.

ResourceBundle loading follows a strict deterministic fallback order: requested language + country, requested language, default locale language + country, default language, and finally the base bundle.

Class-based ResourceBundles take precedence over property-based bundles with identical names and can store arbitrary non-String Java objects.

Individual key lookups within a matched ResourceBundle traverse only that bundle's parent hierarchy to the base bundle; key lookups never fall back to the system default locale bundle.

DateTimeFormatter is immutable and thread-safe; attempting to format a temporal type missing required fields (such as formatting a LocalDate with a time formatter) throws an UnsupportedTemporalTypeException.

Last updated: October 2026

11.4 Internationalization and Localization: Locale , ResourceBundle , and Formatters

Internationalization ( I18N ) is the process of designing software so that it can adapt to various languages and regions without engineering changes. Localization ( L10N ) is the adaptation of that software for a specific geographic or cultural market by translating text and formatting numbers, currencies, dates, and times according to regional conventions. Java SE 17 provides comprehensive localization support through java.util.Locale , java.util.ResourceBundle , java.text.NumberFormat , and java.time.format.DateTimeFormatter .

The Locale Class and Construction

A java.util.Locale object represents a specific geographic, political, or cultural region. It is composed of:

Language Code : Mandatory, 2 or 3 lowercase letters conforming to ISO 639 (e.g., en for English, fr for French, de for German, ja for Japanese).

Country / Region Code : Optional, 2 uppercase letters conforming to ISO 3166 or 3 digits conforming to UN M.49 (e.g., US for United States, CA for Canada, DE for Germany, GB for Great Britain).

Variant / Script : Optional additional markers (e.g., script Latn or variant POSIX ).

  • Instantiation Approaches in Java SE 17 // 1. Static Constants (Predefined for common languages and nations)
  • Locale loc1 = Locale.US; // Language: en, Country: US
  • Locale loc2 = Locale.GERMAN; // Language: de (no country)
  • Locale loc3 = Locale.GERMANY; // Language: de, Country: DE
  • // 2. Public constructors (the standard approach in Java 17)
  • Locale loc4 = new Locale("fr", "CA"); // Language: fr, Country: CA
  • Locale loc5 = new Locale("es"); // Language: es
  • // 3. IETF BCP 47 Language Tag
  • Locale loc6 = Locale.forLanguageTag("zh-CN");
  • // 4. Locale.Builder (Fluent configuration)
  • Locale loc7 = new Locale.Builder()
  • .setLanguage("en")
  • .setRegion("GB")
  • .build();

Note

In Java 17 the public constructors such as new Locale("en", "US") are the normal, non-deprecated way to build a locale, and Locale.of(...) does not exist (javac 17 reports cannot find symbol ). Java 19 later added Locale.of(...) and deprecated the constructors, so newer tutorials look different; answer 1Z0-829 questions using the Java 17 API.

Inspecting and Setting Defaults

The JVM maintains default locales for the active host environment. Java divides the default locale into two categories:

Locale.Category.FORMAT : Governs formatting of numbers, currencies, and dates.

Locale.Category.DISPLAY : Governs localized UI names for languages, countries, and UI strings. Locale defaultLocale = Locale.getDefault();

Locale formatLocale = Locale.getDefault(Locale.Category.FORMAT);

  • // Updating defaults
  • Locale.setDefault(new Locale("fr", "FR"));
  • ResourceBundle Architecture and File Formats

A ResourceBundle manages locale-specific resources (such as translated text messages). Java supports two storage formats for resource bundles:

Property Resource Bundles ( .properties ) : Standard flat text files containing key=value pairs. Values are strictly String objects.

Class Resource Bundles ( .java / .class ) : Concrete classes extending java.util.ListResourceBundle . They define a getContents() method returning Object[][] .

Advantages of Class Bundles

Can contain any Java object type (such as Color , Icon , or byte[] ), whereas .properties files are restricted entirely to strings.

Values can be computed dynamically at runtime.

Precedence Rule : If both a .class bundle and a .properties bundle exist with the identical bundle name for a given locale, the .class bundle always takes precedence over the .properties bundle! // Example Class-Based Bundle: Messages_en.java

  • public class Messages_en extends ListResourceBundle {
  • @Override
  • protected Object[][] getContents() {
  • return new Object[][] {
  • { "welcome", "Welcome to our application!" },

{ "maxItems", 500 } // Can store non-String objects!

  • };
  • }
  • }
  • ResourceBundle Resolution Hierarchy and Fallback Rules

When ResourceBundle.getBundle(baseName, targetLocale) is called, the JVM performs a deterministic search across the classpath to locate the best matching bundle.

The Search Order

Assume the application requests bundle base name AppLabels for new Locale("fr", "CA") (French Canadian), and the system default locale is new Locale("en", "US") :

  • AppLabels_fr_CA (Target language + target country)
  • AppLabels_fr (Target language only)
  • AppLabels_en_US (Default locale language + default country)
  • AppLabels_en (Default locale language only)
  • AppLabels (Base bundle with no locale suffix)

If none of these files exist on the classpath, Java throws java.util.MissingResourceException .

At each step, Java looks for a .class file first, followed by a .properties file.

Key Fallback Mechanics (The Critical Exam Trap)

Once a bundle file is matched, Java selects that bundle family. When you query a specific key using bundle.getString(key) , Java searches that bundle. If the key is missing:

The lookup searches up the inheritance hierarchy of that matched bundle : fr_CA → \rightarrow → fr → \rightarrow → base AppLabels .

It NEVER falls back to the default locale bundle ( en_US or en )! Matched Bundle Family:

  • AppLabels_fr_CA ---> AppLabels_fr ---> AppLabels (Base)
  • |
  • [MissingResourceException]
  • (Never crosses over to AppLabels_en_US!)

Warning

If AppLabels_fr.properties is found, the system default locale AppLabels_en.properties is completely ignored for individual key lookups . If a key exists in AppLabels_en but is absent in both AppLabels_fr and base AppLabels , bundle.getString(key) throws MissingResourceException !

Formatting and Parsing Numbers and Currencies: NumberFormat

The java.text.NumberFormat abstract class formats and parses numbers, percentages, and currencies according to regional conventions.

  • Factory Methods Locale us = Locale.US;
  • Locale germany = Locale.GERMANY;
  • NumberFormat nfUs = NumberFormat.getInstance(us);
  • NumberFormat nfDe = NumberFormat.getInstance(germany);
  • System.out.println(nfUs.format(123456.78)); // 123,456.78 (comma thousands, dot decimal)
  • System.out.println(nfDe.format(123456.78)); // 123.456,78 (dot thousands, comma decimal)
  • // Currency Formatting
  • NumberFormat curUs = NumberFormat.getCurrencyInstance(us);
  • NumberFormat curDe = NumberFormat.getCurrencyInstance(germany);
  • System.out.println(curUs.format(49.99)); // $49.99
  • System.out.println(curDe.format(49.99)); // 49,99 € (comma decimal separator, symbol after a space)
  • Parsing Behavior and Checked Exceptions

The parse(String) method parses text into a java.lang.Number ( Long or Double ). It throws a checked java.text.ParseException if parsing fails:

Prefix Matching : NumberFormat.parse() begins reading from the start of the string. As soon as it encounters a character that is invalid in the given locale, it stops parsing and returns the number accumulated so far ! Trailing unparsed characters are simply ignored.

Invalid Initial Character : If the very first non-whitespace characters cannot be parsed into a number, parse() throws ParseException . NumberFormat nf = NumberFormat.getInstance(Locale.US);

  • Number val1 = nf.parse("45.67xyz"); // Successfully returns 45.67 (stops at 'x')
  • Number val2 = nf.parse("1,000 items"); // Successfully returns 1000 (stops at ' ')
  • // nf.parse("x45.67"); // THROWS java.text.ParseException: Unparseable number: "x45.67"
  • Formatting and Parsing Dates: DateTimeFormatter

The modern java.time.format.DateTimeFormatter replaces legacy SimpleDateFormat . Unlike its predecessor, DateTimeFormatter is immutable and thread-safe .

Predefined and Localized Styles LocalDateTime ldt = LocalDateTime.of(2026, Month.APRIL, 15, 14, 30);

  • // Standard localized formatters using FormatStyle
  • DateTimeFormatter shortDate = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
  • DateTimeFormatter mediumTime = DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM);
  • DateTimeFormatter fullDateTime = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT, FormatStyle.SHORT);
  • System.out.println(shortDate.format(ldt)); // e.g., 4/15/26 in US
  • The UnsupportedTemporalTypeException in Formatting

A DateTimeFormatter configured for dates cannot format a time-only object, and vice versa. Mismatches trigger runtime exceptions: LocalDate date = LocalDate.of(2026, Month.APRIL, 15);

DateTimeFormatter timeFormatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT);

// COMPILES! But throws UnsupportedTemporalTypeException at runtime:

// java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: ClockHourOfAmPm (in a US locale, whose SHORT time pattern is h:mm a)

  • String output = timeFormatter.format(date);
  • Custom Patterns: ofPattern(String)

Custom patterns use case-sensitive symbols:

  • Symbol Meaning Example for April 15, 2026, 14:30:05
  • yyyy / uuuu 4-digit Year 2026
  • MM 2-digit Month (01-12) 04
  • MMM / MMMM Short / Full Month Name Apr / April
  • dd 2-digit Day of Month (01-31) 15
  • HH 24-hour Hour of Day (00-23) 14
  • hh 12-hour Clock Hour (01-12) 02
  • mm Minute of Hour (00-59) 30
  • ss Second of Minute (00-59) 05
  • a AM / PM Marker PM

Warning

Watch out for case sensitivity in custom patterns! MM represents Month , while mm represents Minute . HH represents 24-hour hour , while hh represents 12-hour hour . dd is day of month , whereas DD is day of year ! DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");

String formatted = dtf.format(ldt); // "15/04/2026 14:30"

// Parsing strings into temporal objects:

LocalDate parsedDate = LocalDate.parse("15/04/2026", DateTimeFormatter.ofPattern("dd/MM/yyyy"));

// Note: LocalDate.parse() throws unchecked DateTimeParseException if parsing fails!