Study guide

12.1 Locales and Resource Bundles

Oracle Java SE 21 Developer 1Z0-830

Track your progress as you read

Finished sections get a check mark.

1 Chapter 1: Java Basics, Primitive Types, and Operators

1.1 Program Structure, Primitives, Literals, Scopes, and var 1.2 Operators, Precedence, and Type Casting 1.3 Strings, Text Blocks, and StringBuilder 1.4 Date and Time APIs (java.time)

2 Chapter 2: Controlling Program Flow & Pattern Matching

2.1 Conditional Logic: if-else and Ternary Operators 2.2 Switch Statements and Switch Expressions 2.3 Pattern Matching for switch and instanceof 2.4 Loops and Branching Statements

3 Chapter 3: Object-Oriented Design & Class Architecture

3.1 Class Declarations, Constructors, and Object Lifecycle 3.2 Encapsulation and Access Modifiers 3.3 Inheritance, Method Overriding, and Polymorphism 3.4 Abstract Classes and Interfaces 3.5 Nested, Inner, Local, and Anonymous Classes 3.6 Method Overloading, Overload Resolution, and Varargs

4 Chapter 4: Modern Java Data Modeling: Records, Enums, and Sealed Types

4.1 Java Records, Canonical/Compact Constructors, and Component Accessors 4.2 Java Enums: Fields, Methods, and Abstract Constant-Specific Behavior 4.3 Sealed Classes and Interfaces: permits, final, non-sealed, and Hierarchy Architecture 4.4 Advanced Record Patterns (JEP 440), Nested Deconstruction, and Sealed Hierarchy Exhaustiveness

5 Chapter 5: Exception Handling and Annotations

5.1 Exception Hierarchy: Checked vs. Unchecked Exceptions 5.2 Exception Handling: try, catch, finally, and Multi-Catch 5.3 Resource Management: try-with-resources and AutoCloseable 5.4 Custom Exceptions and Best Practices 5.5 Java Annotations: Built-in, Meta-Annotations, and Custom Types

6 Chapter 6: Generics and the Collections Framework

6.1 Generics Fundamentals and Generic Methods 6.2 Wildcards, Type Bounds, and Type Erasure 6.3 Core Collections: Lists, Sets, Queues, and Maps 6.4 Sequenced Collections in Java 21 6.5 Sorting, Comparable, and Comparator 6.6 Arrays: Creation, Multidimensional Forms, and the Arrays Utility Class

7 Chapter 7: Functional Programming & Lambda Expressions

7.1 Built-in Functional Interfaces in java.util.function 7.2 Lambda Expressions, Variable Scopes, and Effectively Final 7.3 Method References: Four Varieties and Edge Cases 7.4 Working with java.util.Optional

8 Chapter 8: The Stream API and Data Pipelines

8.1 Stream Creation and Intermediate Operations 8.2 Terminal Operations and Reductions 8.3 Advanced Collectors, Grouping, Partitioning, and Teeing 8.4 Primitive Streams and Parallel Stream Processing

9 Chapter 9: Concurrency, Multithreading, and Virtual Threads

9.1 Thread Fundamentals, Creation, and Lifecycle 9.2 Thread Safety, Synchronization, and the Java Memory Model 9.3 Concurrency Utilities: ExecutorService, Callable, and Future 9.4 Concurrent Collections, Atomics, and Explicit Locks 9.5 Virtual Threads in Java 21 (Carrier Threads, Pinning, and Best Practices)

10 Chapter 10: The Java Platform Module System (JPMS)

10.1 Module Architecture and module-info.java Declarations 10.2 Module Directives: requires, exports, opens, provides, and uses 10.3 Modular Compilation, Packaging, and CLI Execution 10.4 Module Types, Migration Strategies, ServiceLoader SPI, and JLink

11 Chapter 11: Java I/O, NIO.2, and Object Serialization

11.1 Classic Java I/O Streams and Readers/Writers 11.2 Java NIO.2 File API: Path, Paths, and File System Operations 11.3 Advanced NIO.2 Stream Operations and Directory Traversal 11.4 Java Object Serialization and Record Serialization

12 Chapter 12: Implementing Localization and Internationalization

12.1 Locales and Resource Bundles 12.2 Formatting and Parsing Numbers, Currencies, Dates, Times, and Messages

12.1 Locales and Resource Bundles

Key Takeaways Explain This Topic AI

A Locale pairs a lowercase ISO 639 language code with an optional uppercase ISO 3166 country code; Java 19 deprecated the Locale constructors in favour of Locale.of, Locale.forLanguageTag, and Locale.Builder.

Locale.getDefault(Category.DISPLAY) and Locale.getDefault(Category.FORMAT) are independent, letting an application show its interface in one language while formatting numbers and dates for another region.

getBundle tries the requested locale from most specific to least specific, then repeats that narrowing for the default locale, and finally the base name alone before throwing MissingResourceException.

Once a bundle is selected, missing keys are resolved through that bundle's parent chain down to the base bundle only; default-locale bundles that were merely candidates are never parents.

getString throws the unchecked MissingResourceException when a key is absent anywhere in the chain and ClassCastException when a ListResourceBundle stores a non-String value.

Last updated: September 2026

Locales and Resource Bundles

Implementing Localization is one of the ten top-level topics on the 1Z0-830 exam, and it is the topic candidates most often skip. The whole objective reads: "Implement localization using locales and resource bundles. Parse and format messages, dates, times, and numbers, including currency and percentage values." This section covers the first sentence; section 12.2 covers the second.

Localization in Java rests on two types. A Locale identifies who the user is - a language, and optionally a region. A ResourceBundle supplies what to show them - the translated text keyed by a stable identifier. Neither one translates anything for you; they select and load the right values.

1. Constructing a Locale

A locale is composed of a language code (lowercase, ISO 639, e.g. fr ), an optional country/region code (uppercase, ISO 3166, e.g. CA ), and an optional variant. The exam expects you to spot a swapped case pattern instantly: Locale.of("FR", "ca") is legal Java but semantically wrong.

Java 19 deprecated the Locale constructors, so Java 21 code should use one of three modern routes: // 1. Static factory (the direct replacement for the deprecated constructors)

  • Locale enUS = Locale.of("en", "US");
  • Locale french = Locale.of("fr");
  • // 2. BCP 47 language tag - note the HYPHEN, not an underscore
  • Locale frCA = Locale.forLanguageTag("fr-CA");
  • System.out.println(frCA.toLanguageTag()); // fr-CA
  • // 3. Builder, for full BCP 47 control
  • Locale deDE = new Locale.Builder()
  • .setLanguage("de")
  • .setRegion("DE")
  • .build();

Predefined constants come in two flavours that are easy to confuse:

  • Constant Language Country toString()
  • Locale.GERMAN de (none) de
  • Locale.GERMANY de DE de_DE
  • Locale.FRENCH fr (none) fr
  • Locale.CANADA_FRENCH fr CA fr_CA

Note that toString() uses underscores while toLanguageTag() uses hyphens - the same distinction that separates a resource bundle file name from a language tag.

  • Default Locales Come in Two Categories Locale.getDefault(); // convenience: the FORMAT default
  • Locale.getDefault(Locale.Category.DISPLAY); // menus, labels, display names
  • Locale.getDefault(Locale.Category.FORMAT); // numbers, currency, dates
  • Locale.setDefault(Locale.of("es", "MX")); // sets BOTH categories

Splitting the two lets an application show its user interface in one language while formatting numbers and dates according to a different regional convention.

getDisplayLanguage() and getDisplayCountry() are themselves localizable, which is a favourite exam nuance: Locale target = Locale.of("de", "DE");

  • System.out.println(target.getDisplayLanguage(Locale.US)); // German
  • System.out.println(target.getDisplayLanguage(Locale.FRANCE)); // allemand
  • System.out.println(target.getLanguage()); // de (never localized)
  • 2. The Two Kinds of ResourceBundle

ResourceBundle is an abstract class with two concrete forms in the standard library.

PropertyResourceBundle is created automatically from a .properties file. You never name the class: # Messages_fr.properties

  • greeting = Bonjour
  • farewell = Au revoir

Since Java 9 these files are read as UTF-8 by default (with a fallback to ISO-8859-1 for legacy files), so accented characters no longer need \\uXXXX escapes.

ListResourceBundle is a Java class, which lets values be any object rather than only strings: public class Messages_ja extends ListResourceBundle {

  • @Override
  • protected Object[][] getContents() {
  • return new Object[][] {
  • { "greeting", "こんにちは" },
  • { "maxItems", 25 } // an Integer, not a String
  • };
  • }
  • }

Loading and reading them is identical either way: ResourceBundle rb = ResourceBundle.getBundle("Messages", Locale.of("fr", "CA"));

String greeting = rb.getString("greeting");

getString(key) throws MissingResourceException (unchecked) when the key is nowhere in the chain, and ClassCastException when the stored value is not a String .

Use getObject(key) for non-string values and getStringArray(key) for String[] .

keySet() returns every key visible through the bundle and its parents ; containsKey(key) is the safe pre-check.

3. Bundle Selection: The Highest-Yield Rule in This Topic

getBundle(baseName, requestedLocale) builds a list of candidate names from most specific to least specific , and takes the first one that exists. At each candidate name it looks for a class first, then a .properties file .

For base name Messages , requested locale fr_CA , and default locale en_US , the search order is: 1. Messages_fr_CA (requested: language + country)

  • 2. Messages_fr (requested: language only)
  • 3. Messages_en_US (default locale: language + country)
  • 4. Messages_en (default locale: language only)
  • 5. Messages (base bundle, no suffix)
  • > otherwise MissingResourceException
  • Key Lookup Uses the Parent Chain, Not the Search List

Once a bundle is chosen, missing keys are resolved by walking that bundle's parent chain , which strips one locale component at a time down to the base bundle. The default-locale bundles are not in the chain unless the match itself came from the default-locale pass.

Given these files:

  • File Keys
  • Messages_fr.properties greeting
  • Messages_en.properties greeting , hint
  • Messages.properties greeting , farewell

and a request for fr_CA with default en_US : ResourceBundle rb = ResourceBundle.getBundle("Messages", Locale.of("fr", "CA"));

  • rb.getString("greeting"); // from Messages_fr - the selected bundle
  • rb.getString("farewell"); // from Messages - via the parent chain
  • rb.getString("hint"); // MissingResourceException - Messages_en is NOT a parent

That last line is the single most commonly tested trap in the localization objective. The en bundle was a candidate during selection, but selection stopped at Messages_fr ; the chain is Messages_fr then Messages , full stop.

4. Practical Rules and Module Considerations

Bundle files live on the classpath (or module path) at the package matching the base name: getBundle("com.app.Messages", ...) resolves com/app/Messages_fr.properties .

In a named module, the module that reads the bundle needs access to those resources; either keep the bundles in the same module, or opens the package holding them.

Keys must be identical across every translation. A key present only in Messages_fr and absent from Messages will fail for every other locale.

Bundles are cached, so repeated getBundle calls with the same base name, locale, and loader return the same instance.

Always provide a base bundle with no locale suffix. Without it, any request whose language matches nothing at all fails with MissingResourceException rather than degrading gracefully.

Loading diagram... Resource Bundle Selection Versus Parent-Chain Key Lookup