Module java.base
Package java.text

Class MessageFormat

java.lang.Object
java.text.Format
java.text.MessageFormat
所有已实现的接口:
Serializable, Cloneable

public class MessageFormat extends Format
MessageFormat 提供了一种以语言中立的方式生成连接消息的方法。使用它来构造显示给最终用户的消息。

MessageFormat 接受一组对象,对它们进行格式化,然后将格式化后的字符串插入到模式中的适当位置。

注意: MessageFormat 与其他 Format 类不同,您使用其构造函数之一创建 MessageFormat 对象(而不是使用 getInstance 风格的工厂方法)。工厂方法是不必要的,因为 MessageFormat 本身不实现特定于区域设置的行为。任何特定于区域设置的行为由您提供的模式以及用于插入参数的子格式定义。

模式及其解释

MessageFormat 使用以下形式的模式:
 MessageFormatPattern:
         String
         MessageFormatPattern FormatElement String

 FormatElement:
         { ArgumentIndex }
         { ArgumentIndex , FormatType }
         { ArgumentIndex , FormatType , FormatStyle }

 FormatType: 其中之一
         number date time choice

 FormatStyle:
         short
         medium
         long
         full
         integer
         currency
         percent
         SubformatPattern
 

在一个 String 中,一对单引号可以用来引用除单引号之外的任意字符。例如,模式字符串 "'{0}'" 表示字符串 "{0}",而不是一个 FormatElement。单引号本身必须通过双单引号 '' 来表示。例如,模式字符串 "'{''}'" 被解释为一个序列 '{(引号开始和左花括号),''(一个单引号),和 }'(右花括号和引号结束),而不是 '{''}'(引号的左花括号和右花括号):表示字符串 "{'}"而不是 "{}"

SubformatPattern 由其对应的子格式解释,并应用于依赖于子格式的模式规则。例如,模式字符串 "{1,number,$'#',##}"(带有下划线的 SubformatPattern)将生成一个带有引号的数值格式,结果可能如下: "$#31,45"。有关详细信息,请参阅每个 Format 子类的文档。

任何未匹配的引号将被视为在给定模式的末尾关闭。例如,模式字符串 "'{0}" 将被视为模式 "'{0}'"

在未引用的模式中的任何花括号必须是平衡的。例如,"ab {0} de""ab '}' de" 是有效模式,但 "ab {0'}' de""ab } de""''{''" 不是。

警告:
遗憾的是,在消息格式模式中使用引号的规则有时会令人感到困惑。特别是,对于本地化人员来说,是否需要将单引号加倍并不总是明显的。确保向本地化人员介绍这些规则,并告诉他们(例如,通过在资源包源文件中使用注释)哪些字符串将由 MessageFormat 处理。请注意,本地化人员可能需要在原始版本中没有的地方在翻译后的字符串中使用单引号。

ArgumentIndex 值是使用数字 '0''9' 编写的非负整数,表示传递给 format 方法的 arguments 数组中的索引,或者由 parse 方法返回的结果数组中的索引。

FormatTypeFormatStyle 值用于创建格式元素的 Format 实例。以下表显示这些值如何映射到 Format 实例。表中未显示的组合是非法的。 SubformatPattern 必须是所使用的 Format 子类的有效模式字符串。

显示 FormatType 和 FormatStyle 值如何映射到 Format 实例
FormatType FormatStyle 创建的子格式
(无) (无) null
number (无) NumberFormat.getInstance(getLocale())
integer NumberFormat.getIntegerInstance(getLocale())
currency NumberFormat.getCurrencyInstance(getLocale())
percent NumberFormat.getPercentInstance(getLocale())
SubformatPattern new DecimalFormat(subformatPattern, DecimalFormatSymbols.getInstance(getLocale()))
date (无) DateFormat.getDateInstance(DateFormat.DEFAULT, getLocale())
short DateFormat.getDateInstance(DateFormat.SHORT, getLocale())
medium DateFormat.getDateInstance(DateFormat.DEFAULT, getLocale())
long DateFormat.getDateInstance(DateFormat.LONG, getLocale())
full DateFormat.getDateInstance(DateFormat.FULL, getLocale())
SubformatPattern new SimpleDateFormat(subformatPattern, getLocale())
time (无) DateFormat.getTimeInstance(DateFormat.DEFAULT, getLocale())
short DateFormat.getTimeInstance(DateFormat.SHORT, getLocale())
medium DateFormat.getTimeInstance(DateFormat.DEFAULT, getLocale())
long DateFormat.getTimeInstance(DateFormat.LONG, getLocale())
full DateFormat.getTimeInstance(DateFormat.FULL, getLocale())
SubformatPattern new SimpleDateFormat(subformatPattern, getLocale())
choice SubformatPattern new ChoiceFormat(subformatPattern)

使用信息

以下是一些使用示例。在真实的国际化程序中,消息格式模式和其他静态字符串当然将从资源包中获取。其他参数将在运行时动态确定。

第一个示例使用静态方法 MessageFormat.format,它在内部创建一个用于一次性使用的 MessageFormat

int planet = 7;
String event = "a disturbance in the Force";

String result = MessageFormat.format(
    "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
    planet, new Date(), event);
输出为:
 At 12:30 PM on Jul 3, 2053, there was a disturbance in the Force on planet 7.
 

以下示例创建一个可以重复使用的 MessageFormat 实例:

int fileCount = 1273;
String diskName = "MyDisk";
Object[] testArgs = {Long.valueOf(fileCount), diskName};

MessageFormat form = new MessageFormat(
    "磁盘 \"{1}\" 包含 {0} 个文件。");

System.out.println(form.format(testArgs));
不同值的输出为 fileCount:
 磁盘 "MyDisk" 包含 0 个文件。
 磁盘 "MyDisk" 包含 1 个文件。
 磁盘 "MyDisk" 包含 1,273 个文件。
 

对于更复杂的模式,您可以使用 ChoiceFormat 来生成正确的单数和复数形式:

MessageFormat form = new MessageFormat("磁盘 \"{1}\" 包含 {0}.");
double[] filelimits = {0,1,2};
String[] filepart = {"没有文件","一个文件","{0,number} 个文件"};
ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
form.setFormatByArgumentIndex(0, fileform);

int fileCount = 1273;
String diskName = "MyDisk";
Object[] testArgs = {Long.valueOf(fileCount), diskName};

System.out.println(form.format(testArgs));
不同值的输出为 fileCount:
 磁盘 "MyDisk" 包含没有文件。
 磁盘 "MyDisk" 包含一个文件。
 磁盘 "MyDisk" 包含 1,273 个文件。
 

您可以像上面的示例那样通过编程方式创建 ChoiceFormat,也可以使用模式。有关更多信息,请参阅 ChoiceFormat

form.applyPattern(
   "有{0,choice,0#没有文件|1#一个文件|1< {0,number,integer} 个文件}.");

注意: 如上所示,在 MessageFormat 中由 ChoiceFormat 生成的字符串被视为特殊;'{' 的出现用于指示子格式,并导致递归。如果您通过编程方式创建 MessageFormatChoiceFormat(而不是使用字符串模式),请小心不要生成递归自身的格式,这将导致无限循环。

当一个参数在字符串中被多次解析时,最后一次匹配将是解析的最终结果。例如,

MessageFormat mf = new MessageFormat("{0,number,#.##}, {0,number,#.#}");
Object[] objs = {Double.valueOf(3.1415)};
String result = mf.format( objs );
// 现在 result 等于 "3.14, 3.1"
objs = mf.parse(result, new ParsePosition(0));
// objs 现在等于 {Double.valueOf(3.1)}

同样,使用包含同一参数多次出现的模式进行解析的 MessageFormat 对象将返回最后一次匹配。例如,

MessageFormat mf = new MessageFormat("{0}, {0}, {0}");
String forParsing = "x, y, z";
Object[] objs = mf.parse(forParsing, new ParsePosition(0));
// objs 现在等于 {new String("z")}

同步

消息格式不是同步的。建议为每个线程创建单独的格式实例。如果多个线程同时访问一个格式,必须在外部进行同步。

自 JDK 版本:
1.1
参见:
  • Constructor Details

    • MessageFormat

      public MessageFormat(String pattern)
      为默认的 FORMAT 区域设置和指定模式构造了一个 MessageFormat。构造函数首先设置区域设置,然后解析模式并为其中包含的格式元素创建子格式列表。模式及其解释在类描述中指定。
      参数:
      pattern - 此消息格式的模式
      抛出:
      IllegalArgumentException - 如果模式无效
      NullPointerException - 如果 patternnull
    • MessageFormat

      public MessageFormat(String pattern, Locale locale)
      为指定的区域设置和模式构造了一个 MessageFormat。构造函数首先设置区域设置,然后解析模式并为其中包含的格式元素创建子格式列表。模式及其解释在类描述中指定。
      实现要求:
      默认实现在创建 MessageFormat 对象期间或稍后由使用具有空区域设置的 MessageFormat 实例调用 format() 时抛出 NullPointerException,并且实现使用依赖于区域设置的子格式。
      参数:
      pattern - 此消息格式的模式
      locale - 此消息格式的区域设置
      抛出:
      IllegalArgumentException - 如果模式无效
      NullPointerException - 如果 patternlocalenull,并且实现使用依赖于区域设置的子格式。
      自 JDK 版本:
      1.4
  • Method Details

    • setLocale

      public void setLocale(Locale locale)
      设置在创建或比较子格式时使用的区域设置。这会影响后续调用
      • applyPatterntoPattern 方法,如果格式元素指定格式类型,因此在 applyPattern 方法中创建子格式,以及
      • formatformatToCharacterIterator 方法,如果格式元素不指定格式类型,因此在格式化方法中创建子格式。
      已经创建的子格式不受影响。
      参数:
      locale - 创建或比较子格式时要使用的区域设置
    • getLocale

      public Locale getLocale()
      获取在创建或比较子格式时使用的区域设置。
      返回:
      创建或比较子格式时使用的区域设置
    • applyPattern

      public void applyPattern(String pattern)
      设置此消息格式使用的模式。该方法解析模式并为其中包含的格式元素创建子格式列表。模式及其解释在类描述中指定。
      参数:
      pattern - 此消息格式的模式
      抛出:
      IllegalArgumentException - 如果模式无效
      NullPointerException - 如果 patternnull
    • toPattern

      public String toPattern()
      返回表示消息格式当前状态的模式。该字符串是从内部信息构造的,因此不一定等于先前应用的模式。
      返回:
      表示消息格式当前状态的模式
    • setFormatsByArgumentIndex

      public void setFormatsByArgumentIndex(Format[] newFormats)
      设置用于传递给 format 方法或从 parse 方法返回的值所使用的格式。 newFormats 中元素的索引对应于先前设置的模式字符串中使用的参数索引。因此,newFormats 中的格式顺序对应于传递给 format 方法的 arguments 数组中的元素顺序,或者由 parse 方法返回的结果数组的顺序。

      如果一个参数索引用于模式字符串中的多个格式元素,则所有这些格式元素都使用相应的新格式。如果参数索引未用于模式字符串中的任何格式元素,则忽略相应的新格式。如果提供的格式比所需的少,则只替换小于 newFormats.length 的参数索引的格式。

      参数:
      newFormats - 要使用的新格式
      抛出:
      NullPointerException - 如果 newFormats 为 null
      自 JDK 版本:
      1.4
    • setFormats

      public void setFormats(Format[] newFormats)
      设置用于先前设置的模式字符串中格式元素的格式。 newFormats 中的格式顺序对应于模式字符串中格式元素的顺序。

      如果提供的格式比模式字符串所需的多,则忽略剩余的格式。如果提供的格式比所需的少,则只替换前 newFormats.length 个格式。

      由于模式字符串中格式元素的顺序在本地化过程中经常发生变化,因此通常最好使用setFormatsByArgumentIndex方法,该方法假定格式的顺序与传递给 format 方法的 arguments 数组的顺序相对应,或者与 parse 方法返回的结果数组的顺序相对应。

      参数:
      newFormats - 要使用的新格式
      抛出:
      NullPointerException - 如果 newFormats 为 null
    • setFormatByArgumentIndex

      public void setFormatByArgumentIndex(int argumentIndex, Format newFormat)
      设置用于先前设置的模式字符串中使用给定参数索引的格式。参数索引是格式元素定义的一部分,表示传递给 format 方法的 arguments 数组中的索引,或者由 parse 方法返回的结果数组中的索引。

      如果参数索引用于模式字符串中的多个格式元素,则所有这些格式元素都使用新格式。如果参数索引未用于模式字符串中的任何格式元素,则忽略新格式。

      参数:
      argumentIndex - 要使用新格式的参数索引
      newFormat - 要使用的新格式
      自1.4版本起:
      1.4
    • setFormat

      public void setFormat(int formatElementIndex, Format newFormat)
      设置要在先前设置的模式字符串中给定格式元素索引处使用的格式。格式元素索引是从模式字符串的开头开始计数的基于零的格式元素编号。

      由于模式字符串中格式元素的顺序在本地化过程中经常发生变化,通常最好使用setFormatByArgumentIndex方法,该方法根据它们指定的参数索引访问格式元素。

      参数:
      formatElementIndex - 模式中格式元素的索引
      newFormat - 用于指定格式元素的格式
      抛出:
      ArrayIndexOutOfBoundsException - 如果formatElementIndex等于或大于模式字符串中的格式元素数量
    • getFormatsByArgumentIndex

      public Format[] getFormatsByArgumentIndex()
      获取传递给format方法或从parse方法返回的值所使用的格式。返回数组中的元素索引对应于先前设置的模式字符串中使用的参数索引。因此,返回数组中的格式顺序与传递给format方法的arguments数组中的元素顺序或由parse方法返回的结果数组中的元素顺序相对应。

      如果一个参数索引用于模式字符串中的多个格式元素,则返回数组中将返回最后一个这样的格式元素使用的格式。如果参数索引未用于模式字符串中的任何格式元素,则返回数组中将返回null。

      返回:
      模式中使用的格式
      自1.4版本起:
      1.4
    • getFormats

      public Format[] getFormats()
      获取先前设置的模式字符串中使用的格式元素的格式。返回数组中的格式顺序与模式字符串中的格式元素顺序相对应。

      由于模式字符串中格式元素的顺序在本地化过程中经常发生变化,通常最好使用getFormatsByArgumentIndex方法,该方法假定格式的顺序与传递给format方法的arguments数组中的元素顺序或由parse方法返回的结果数组中的元素顺序相对应。

      返回:
      模式中使用的格式元素的格式
    • format

      public final StringBuffer format(Object[] arguments, StringBuffer result, FieldPosition pos)
      格式化对象数组并将MessageFormat的模式附加到提供的StringBuffer中,其中格式元素由格式化后的对象替换。

      替换为各个格式元素的文本源自格式元素的当前子格式和由表格的第一行中的第一个匹配行指示的格式元素的参数索引处的arguments元素。如果argumentsnull或少于argumentIndex+1个元素,则参数为不可用

      子格式、参数和格式化文本示例
      子格式 参数 格式化文本
      任意 不可用 "{" + argumentIndex + "}"
      null "null"
      ChoiceFormat的实例 任意 subformat.format(argument).indexOf('{') >= 0 ?
      (new MessageFormat(subformat.format(argument), getLocale())).format(argument) : subformat.format(argument)
      != null 任意 subformat.format(argument)
      null Number的实例 NumberFormat.getInstance(getLocale()).format(argument)
      Date的实例 DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, getLocale()).format(argument)
      String的实例 argument
      任意 argument.toString()

      如果pos非空,并且引用Field.ARGUMENT,将返回第一个格式化字符串的位置。

      参数:
      arguments - 要格式化和替换的对象数组
      result - 要附加文本的位置
      pos - 跟踪输出字符串中第一个替换参数的位置
      返回:
      作为result传入的字符串缓冲区,附加了格式化的文本
      抛出:
      IllegalArgumentException - 如果arguments数组中的参数不是格式元素所期望的类型
      NullPointerException - 如果resultnull,或者调用此方法的MessageFormat实例的区域设置为null,并且实现使用区域设置相关的子格式。
    • format

      public static String format(String pattern, Object... arguments)
      使用给定的模式创建一个MessageFormat,并使用它来格式化给定的参数。这等效于
      (new MessageFormat(pattern)).format(arguments, new StringBuffer(), null).toString()
      参数:
      pattern - 模式字符串
      arguments - 要格式化的对象
      返回:
      格式化后的字符串
      抛出:
      IllegalArgumentException - 如果模式无效,或者arguments数组中的参数不是格式元素所期望的类型
      NullPointerException - 如果patternnull
    • format

      public final StringBuffer format(Object arguments, StringBuffer result, FieldPosition pos)
      格式化对象数组并将MessageFormat的模式附加到提供的StringBuffer中,其中格式元素由格式化后的对象替换。这等效于
      format((Object[]) arguments, result, pos)
      在类中指定:
      format 在类 Format
      参数:
      arguments - 要格式化和替换的对象数组
      result - 要附加文本的位置
      pos - 跟踪输出字符串中第一个替换参数的位置
      返回:
      作为toAppendTo传入的字符串缓冲区,附加了格式化的文本
      抛出:
      IllegalArgumentException - 如果arguments数组中的参数不是格式元素所期望的类型
      NullPointerException - 如果resultnull,或者调用此方法的MessageFormat实例的区域设置为null,并且实现使用区域设置相关的子格式。
    • formatToCharacterIterator

      public AttributedCharacterIterator formatToCharacterIterator(Object arguments)
      格式化对象数组并将它们插入到MessageFormat的模式中,生成一个AttributedCharacterIterator。您可以使用返回的AttributedCharacterIterator来构建生成的字符串,以及确定有关生成的字符串的信息。

      返回的AttributedCharacterIterator的文本与以下内容相同

      format(arguments, new StringBuffer(), null).toString()

      此外,AttributedCharacterIterator包含至少指示文本是从arguments数组中的参数生成的位置的属性。这些属性的键是MessageFormat.Field类型,它们的值是Integer对象,指示生成文本的参数在arguments数组中的索引。

      MessageFormat使用的底层Format实例的属性/值也将放置在生成的AttributedCharacterIterator中。这使您不仅可以找到参数在生成的字符串中的位置,还可以找到它包含的字段。

      覆盖:
      formatToCharacterIterator 在类 Format
      参数:
      arguments - 要格式化和替换的对象数组。
      返回:
      描述格式化值的AttributedCharacterIterator。
      抛出:
      NullPointerException - 如果arguments为null。
      IllegalArgumentException - 如果arguments数组中的参数不是格式元素所期望的类型。
      自:
      1.4
    • parse

      public Object[] parse(String source, ParsePosition pos)
      解析字符串。

      注意事项:解析可能在许多情况下失败。例如:

      • 如果一个参数不在模式中出现。
      • 如果参数的格式丢失信息,例如在选择格式中,一个大数字格式为"many"。
      • 尚未处理递归(其中替换的字符串包含{n}引用)。
      • 如果解析的某部分存在歧义,则不会始终找到匹配项(或正确的匹配项)。例如,如果将模式"{1},{2}"与字符串参数{"a,b", "c"}一起使用,则格式化为"a,b,c"。当解析结果时,将返回{"a", "b,c"}。
      • 如果单个参数在字符串中被解析多次,则后续解析将获胜。
      当解析失败时,使用ParsePosition.getErrorIndex()来查找解析失败的字符串位置。返回的错误索引是字符串正在比较的子模式的起始偏移量。例如,如果解析字符串"AAA {0} BBB"与模式"AAD {0} BBB"进行比较,则错误索引为0。发生错误时,调用此方法将返回null。如果源为null,则返回一个空数组。
      参数:
      source - 要解析的字符串
      pos - 解析位置
      返回:
      解析后的对象数组
      抛出:
      NullPointerException - 如果pos为非null的source字符串。
    • parse

      public Object[] parse(String source) throws ParseException
      从给定字符串的开头解析文本以生成对象数组。该方法可能不使用给定字符串的全部文本。

      有关消息解析的更多信息,请参阅parse(String, ParsePosition)方法。

      参数:
      source - 应该解析其开头的String
      返回:
      从字符串解析的Object数组
      抛出:
      ParseException - 如果无法解析指定字符串的开头。
    • parseObject

      public Object parseObject(String source, ParsePosition pos)
      从字符串解析文本以生成对象数组。

      该方法尝试从由pos给定的索引开始解析文本。如果解析成功,则pos的索引将更新为使用的最后一个字符之后的索引(解析不一定使用到字符串末尾的所有字符),并返回解析的对象数组。更新后的pos可以用于指示下一次调用此方法的起始点。如果发生错误,则pos的索引不会更改,pos的错误索引设置为发生错误的字符的索引,并返回null。

      有关消息解析的更多信息,请参阅parse(String, ParsePosition)方法。

      指定者:
      parseObject 在类 Format
      参数:
      source - 应解析其中一部分的String
      pos - 一个ParsePosition对象,其中包含上述索引和错误索引信息。
      返回:
      从字符串解析的Object数组。在发生错误时,返回null。
      抛出:
      NullPointerException - 如果pos为null。
    • clone

      public Object clone()
      创建并返回此对象的副本。
      覆盖:
      clone 在类 Format
      返回:
      此实例的克隆。
      参见:
    • equals

      public boolean equals(Object obj)
      两个消息格式对象之间的相等比较
      覆盖:
      equals 在类 Object
      参数:
      obj - 要比较的参考对象。
      返回:
      如果此对象与obj参数相同,则返回true;否则返回false
      参见:
    • hashCode

      public int hashCode()
      为消息格式对象生成哈希码。
      覆盖:
      hashCode 在类 Object
      返回:
      此对象的哈希码值。
      参见: