杰瑞科技汇

Java MessageFormat如何实现动态消息模板化?

Of course! java.text.MessageFormat is a powerful and versatile class in Java for creating and formatting strings with dynamic data. It's part of the standard Java library (java.text) and is designed to handle internationalization (i18n) and localization (l10n) gracefully.

Java MessageFormat如何实现动态消息模板化?-图1
(图片来源网络,侵删)

Let's break it down, from the basics to more advanced use cases.

What is MessageFormat?

At its core, MessageFormat allows you to create template strings with placeholders. You then provide the actual values for these placeholders, and MessageFormat inserts them into the template, applying necessary formatting rules.

The key advantage over simple string concatenation () or String.format() is its ability to handle grammatical variations based on the input data (e.g., singular vs. plural, gender).


Basic Syntax

The pattern string uses curly braces to mark placeholders. The simplest form is {0}, {1}, {2}, etc., where the number corresponds to the index of the argument in the Object array you provide.

Java MessageFormat如何实现动态消息模板化?-图2
(图片来源网络,侵删)

Example: Simple Formatting

import java.text.MessageFormat;
import java.util.Date;
public class MessageFormatDemo {
    public static void main(String[] args) {
        // 1. Simple argument replacement
        String pattern = "Hello, {0}! Your balance is {1, number, currency}.";
        Object[] arguments = {"Alice", 12345.67};
        String formattedMessage = MessageFormat.format(pattern, arguments);
        System.out.println(formattedMessage);
        // Output: Hello, Alice! Your balance is $12,345.67. (Assuming default Locale)
    }
}

Explanation:

  • {0} is replaced by the first element of the arguments array ("Alice").
  • {1, number, currency} is more complex. It tells MessageFormat to:
    • Take the argument at index 1 (67).
    • Format it as a number.
    • Use the currency subformat.

Placeholders: The Anatomy of {argumentNumber, formatType, formatStyle}

A placeholder can have three optional parts, separated by commas:

{argumentNumber, formatType, formatStyle}

  1. argumentNumber: The index of the argument in the Object[] array (e.g., 0, 1, 2). This is mandatory.

    Java MessageFormat如何实现动态消息模板化?-图3
    (图片来源网络,侵删)
  2. formatType: The general type of formatting to apply. Common types include:

    • number: Formats the argument as a number. You can specify a formatStyle.
    • date: Formats the argument as a date.
    • time: Formats the argument as a time.
    • choice: A special type for handling plurals and grammatical choices (see advanced section).
  3. formatStyle: The specific style for the formatType. This can be:

    • A predefined keyword like integer, currency, percent, short, medium, long, full.
    • A custom pattern string (e.g., for numbers or dates).

Example: Different Format Types

import java.text.MessageFormat;
import java.util.Date;
public class MessageFormatTypes {
    public static void main(String[] args) {
        Object[] arguments = {987654321L, new Date(), 0.75};
        // Number formatting
        String numberPattern = "The number is {0, number}. As currency: {0, number, currency}. As percent: {0, number, percent}.";
        System.out.println(MessageFormat.format(numberPattern, arguments[0]));
        // Output: The number is 987,654,321. As currency: $987,654,321.00. As percent: 75,000%.
        // Date formatting
        String datePattern = "Today is {0, date, long}.";
        System.out.println(MessageFormat.format(datePattern, arguments[1]));
        // Output: Today is October 26, 2025. (Example date)
        // Custom number pattern
        String customPattern = "Custom format: {0, number, #,###.00}";
        System.out.println(MessageFormat.format(customPattern, 12345.678));
        // Output: Custom format: 12,345.68
    }
}

Advanced Feature: Plurals and Grammatical Choice (choice)

This is where MessageFormat truly shines. The choice format type allows you to define different output strings based on a numeric value, most commonly to handle singular and plural forms.

The syntax for the choice format is a bit different. You define a set of ranges, and for each range, you provide a template string.

Syntax: {argumentNumber, choice, min|template#max|template}

Example: Handling Plurals

Let's say we want to display a message about the number of files downloaded.

import java.text.MessageFormat;
public class MessageFormatChoice {
    public static void main(String[] args) {
        String choicePattern = "There {0, choice, 0#are no files|1#is one file|1<are {0, number, integer} files}.";
        // Test with 0 files
        System.out.println(MessageFormat.format(choicePattern, 0));
        // Output: There are no files.
        // Test with 1 file
        System.out.println(MessageFormat.format(choicePattern, 1));
        // Output: There is one file.
        // Test with 5 files
        System.out.println(MessageFormat.format(choicePattern, 5));
        // Output: There are 5 files.
        // Test with 1234 files
        System.out.println(MessageFormat.format(choicePattern, 1234));
        // Output: There are 1,234 files.
    }
}

Explanation of the pattern: {0, choice, 0#are no files|1#is one file|1<are {0, number, integer} files}

  • 0#are no files: If the argument at index 0 is in the range 0 <= x < 1, use the template "are no files".
  • 1#is one file: If the argument is in the range 1 <= x < 1 (i.e., exactly 1), use the template "is one file".
  • 1<are {0, number, integer} files: If the argument is in the range x > 1, use the template "are {0, number, integer} files". Notice you can even nest another format specifier inside the choice template!

Internationalization (i18n) and Locale

MessageFormat is Locale-aware. The formatting of numbers, currencies, and dates changes based on the Locale you provide. This is crucial for building applications for a global audience.

Example: Locale Sensitivity

import java.text.MessageFormat;
import java.util.Locale;
public class MessageFormatLocale {
    public static void main(String[] args) {
        double amount = 1500.50;
        Object[] arguments = {amount};
        // Pattern for formatting a currency amount
        String pattern = "The price is {0, number, currency}.";
        // Format for US Locale
        MessageFormat usFormat = new MessageFormat(pattern, Locale.US);
        System.out.println(usFormat.format(arguments));
        // Output: The price is $1,500.50.
        // Format for French Locale (France)
        MessageFormat frFormat = new MessageFormat(pattern, Locale.FRANCE);
        System.out.println(frFormat.format(arguments));
        // Output: The price is 1 500,50 €.
        // Note: The space and comma/decimal point separators are different.
        // Format for German Locale (Germany)
        MessageFormat deFormat = new MessageFormat(pattern, Locale.GERMANY);
        System.out.println(deFormat.format(arguments));
        // Output: The price is 1.500,50 €.
    }
}

MessageFormat vs. String.format()

It's common to wonder which one to use. Here's a quick comparison:

Feature MessageFormat String.format()
Primary Use Case User-facing messages (labels, notifications, logs). Programmatic string construction (e.g., SQL queries, file paths).
Argument Indexing Named by position: {0}, {1}. Order in the array matters. Named by position: %1$s, %2$d. Order in the argument list matters.
Pluralization/Grammar Excellent, built-in support via the choice format. No built-in support. You must implement it manually with if/else or ternary operators.
Formatting Rich, Locale-aware formatting for numbers, dates, and times. Very powerful and precise formatting via format specifiers (e.g., %d, %f, %tF).
Performance Generally slower due to parsing the pattern. Generally faster for simple, repeated formatting.
Complexity Pattern syntax can be complex,
分享:
扫描分享到社交APP
上一篇
下一篇