java.text.MessageFormat 是 Java 標準庫中強大的訊息格式化工具,支援參數索引、型別格式化(數字、日期、選擇)、巢狀模式與區域敏感輸出。它廣泛用於國際化 (i18n)、日誌模板、SQL 參數化等場景。本文將系統解析其語法規則,並透過豐富範例展示進階用法與常見陷阱。
模式字串由 FormatElement 組成,基本形式:
{ArgumentIndex}
{ArgumentIndex, FormatType}
{ArgumentIndex, FormatType, FormatStyle}
| 元素 | 說明 | 常用值 |
|---|---|---|
| ArgumentIndex | 參數索引,從 0 起算,可超過 9 (如 {10}) | 0, 1, 2… |
| FormatType | 指定格式化器 | number, date, time, choice |
| FormatStyle | 格式化風格 | short, medium, long, full, integer, currency, percent, 或子模式如 #.## |
String msg = "{0}{1}{2}{3}{4}{5}{6}{7}{8}";
Object[] args = {"A","B","C","D","E","F","G","H","I"};
String result = MessageFormat.format(msg, args);
// 輸出:ABCDEFGHI
// 保留一位小數
MessageFormat.format("值:{0,number,#.#}", 3.1415); // 值:3.1
// 貨幣格式 (依 Locale)
MessageFormat.format("價格:{0,number,currency}", 1234.5); // 價格:$1,234.50 (en_US)
// 百分比
MessageFormat.format("進度:{0,number,percent}", 0.856); // 進度:86%
Date now = new Date();
MessageFormat.format("今天:{0,date,long}", now); // 今天:2024年1月15日
MessageFormat.format("時間:{0,time,short}", now); // 時間:下午3:30
MessageFormat 以單引號 ' 作為跳脫字元,規則如下:
'' → 輸出單個單引號 '' → 被忽略,且會使其後的格式元素失效 (視為純文字)\" 無特殊意義,直接輸出// 輸出:oh, ZhangSan is 'a' pig
MessageFormat.format("oh, {0} is ''a'' pig", "ZhangSan");
// 輸出:oh, ZhangSan is a pig (單引號被吃掉)
MessageFormat.format("oh, {0} is 'a' pig", "ZhangSan");
// 輸出:{0}-2 (首單引號導致 {0} 失效)
MessageFormat.format("'{0}-{1}", 1, 2);
} 可直接使用{ 必須用單引號包裹:'{'// 輸出:{X-rapido}
MessageFormat.format("'{'{0}}", "X-rapido");
靜態 MessageFormat.format(pattern, args) 內部每次都會 `new MessageFormat(pattern)`,高頻呼叫會產生大量物件。建議:
// 建立一次,多次使用
MessageFormat mf = new MessageFormat("用戶 {0} 於 {1,time,medium} 登入");
for (LogEntry e : logs) {
String line = mf.format(new Object[]{e.user, e.timestamp});
writer.println(line);
}
適用於複數形式、區間顯示等場景:
String pattern = "檔案數:{0,choice,0#無檔案|1#一個檔案|1<多個檔案}";
MessageFormat mf = new MessageFormat(pattern);
System.out.println(mf.format(new Object[]{0})); // 無檔案
System.out.println(mf.format(new Object[]{1})); // 一個檔案
System.out.println(mf.format(new Object[]{5})); // 多個檔案
ArrayIndexOutOfBoundsException。Date 使用 number 會拋出 IllegalArgumentException。'' 輸出單引號。MessageFormat 非執行緒安全,多執行緒環境下請各自建立實例或同步存取。MessageFormat 以聲明式模板解決複雜字串組裝需求,特別適合國際化訊息、報表模板、動態 SQL 片段產生。掌握 FormatType/FormatStyle/ChoiceFormat 三大支柱,並養成重用實例、正確跳脫特殊字元的習慣,即能發揮其最大效能。