ChoiceFormat是Java中根据数值范围匹配字符串的工具类,通过边界数组与格式数组(或模式字符串)实现单复数、状态分级等本地化表达,常与MessageFormat结合嵌入动态变量。`ChoiceFormat` 是 Java 中用于根据数值范围匹配对应字符串的工具类,常用于实现“1 个苹果、2 个苹果、5 个苹果”这类带数量逻辑的本地化表达,尤其适合处理单复数、状态分级(如“低/中/高”)、评分等级(如“不及格/及格/良好/优秀”)等场景。
它的核心机制是:**用一个数值数组定义边界点,再用一个字符串数组定义每个区间对应的输出**。匹配规则是“小于等于该边界值,且大于前一个边界值”的区间(左开右闭),第一个值默认为负无穷下界。
构造 ChoiceFormat 的基本方式
最常用的是通过 `new ChoiceFormat(double[] limits, String[] formats)` 构造,注意两点:
- limits 数组必须升序排列,长度应比 formats 少 1(即 n 个边界点划分出 n+1 个区间)
- formats 长度 = limits.length + 1,索引 0 对应 (-∞, limits[0]],索引 1 对应 (limits[0], limits[1]],以此类推
例如实现“苹果”单复数:
double[] limits = {1}; // 边界:1
String[] formats = {"1 个苹果", "0 个苹果或多个苹果"}; // 2 个字符串
ChoiceFormat cf = new ChoiceFormat(limits, formats);
System.out.println(cf.format(0)); // → "0 个苹果或多个苹果" (0 ≤ 1 → 匹配第0个?错!注意:0 1 → 属于 (1, ∞) → 索引1)
⚠️ 上面例子其实没真正区分“1 个”和“多个”,因为 1 落在第一个区间。要让 1 单独成一类,需调整边界:
double[] limits = {1, 2}; // 两个边界:1 和 2
String[] formats = {"0 个苹果", "1 个苹果", "2 个及以上苹果"};
// 区间:(-∞,1] → "0 个苹果"
// (1,2] → "1 个苹果"
// (2,∞) → "2 个及以上苹果"
System.out.println(cf.format(0)); // "0 个苹果"
System.out.println(cf.format(1)); // "1 个苹果" ← 注意:1 落在 (1,2]?不,1 不满足 >1 → 实际仍属 (-∞,1]
✅ 正确写法是把边界设为 {0, 1} 或 {1, 2} 并理解其开闭性。更清晰的做法是用 显式区间语法(推荐):
使用模式字符串构造(更直观)
直接传入类似 "0#没有苹果|1#1 个苹果|2#多个苹果" 的 pattern 字符串,其中 # 前是下限(含),| 分隔不同规则:
-
0#...表示 ≥ 0 的所有数都匹配这一项(作为起点) -
1#...表示 ≥ 1 且 -
2#...表示 ≥ 2 的所有数
完整示例(支持 0/1/≥2):
String pattern = "0#没有苹果|1#1 个苹果|2#多个苹果"; ChoiceFormat cf = new ChoiceFormat(pattern); System.out.println(cf.format(0)); // "没有苹果" System.out.println(cf.format(1)); // "1 个苹果" System.out.println(cf.format(5)); // "多个苹果"
✅ 模式语法本质是自动转为 limits/formats 数组:"0#A|1#B|2#C" → limits=[0,1,2], formats=["A","B","C"],匹配逻辑为:
x ∈ (-∞,0] → A
x ∈ (0,1] → B
x ∈ (1,2] → C
x > 2 → C(最后一个 format 覆盖剩余全部)
处理中文单复数与常见状态分级
不只是数量,还可映射任意数值区间到描述词:
-
评分等级:
"0#不及格|60#及格|80#良好|90#优秀"→ 59→“不及格”,60→“及格”,85→“良好”,95→“优秀” -
温度状态:
"-273#绝对零度|0#冰点|100#沸点|1000#高温" -
用户活跃度:
"0#沉寂用户|1#新用户|10#活跃用户|100#核心用户"
注意:ChoiceFormat 只做数值比较,不解析单位或文本。若需支持小数(如 1.5 个苹果),模式依然有效:"0#无|1#单个|2#多个" → format(1.0) → “单个”,format(1.5) → “多个”(因 1.5 > 1 且 ≤2)
结合 MessageFormat 实现占位动态组合
单独用 ChoiceFormat 输出纯文字;若需嵌入变量(如“您有 {0} 条未读消息”),应搭配 MessageFormat:
String pattern = "0#没有未读消息|1#有 1 条未读消息|2#有 {0} 条未读消息";
ChoiceFormat cf = new ChoiceFormat(pattern);
MessageFormat mf = new MessageFormat("您{0}。", Locale.getDefault());
mf.setFormatByArgumentIndex(0, cf);
System.out.println(mf.format(new Object[]{0})); // "您没有未读消息。"
System.out.println(mf.format(new Object[]{1})); // "您有 1 条未读消息。"
System.out.println(mf.format(new Object[]{5})); // "您有 5 条未读消息。"
这里 {0} 在 pattern 中被 ChoiceFormat 解析,再传给 MessageFormat 做最终拼接,实现真正的动态文本生成。










