
本文介绍使用 Java Stream API 将键具有相同前缀(如 "a.1", "a.2" → 前缀 "a")的 Map 条目按前缀归类,并将对应的所有 List 值合并为嵌套列表,最终生成前缀到 List 的分组映射。
本文介绍使用 java stream api 将键具有相同前缀(如 "a.1", "a.2" → 前缀 "a")的 map 条目按前缀归类,并将对应的所有 list 值合并为嵌套列表,最终生成前缀到 list> 的分组映射。
在实际开发中,我们常遇到一类结构化键名的 Map 数据,例如 "a.01"、"a.02"、"b.01" 等,其语义上由「前缀 + 分隔符 + 后缀」构成。若需按前缀(如 "a"、"b")聚合所有关联的 List 值,标准 Map 本身不支持自动分组,但借助 Java 8+ 的 Stream API 可以简洁、函数式地实现。
核心思路是:
- 使用 Collectors.groupingBy() 按前缀提取逻辑分组;
- 前缀提取可通过 key.substring(0, key.indexOf('.'))(更健壮)或 key.substring(0, 1)(适用于单字符前缀且格式严格)实现;
- 使用 Collectors.mapping() 将每个 Map.Entry 的 value(即原始 List
)映射出来,并通过 Collectors.toList() 收集为 List - >。
以下是完整可运行示例(适配通用场景,已增强健壮性):
import java.util.*;
import java.util.stream.Collectors;
public class PrefixGrouping {
public static <t> Map<string list>>> groupByPrefix(Map<string list>> input) {
if (input == null) return Collections.emptyMap();
return input.entrySet().stream()
.filter(entry -> entry.getKey() != null && !entry.getKey().isEmpty())
.collect(Collectors.groupingBy(
entry -> {
String key = entry.getKey();
int dotIndex = key.indexOf('.');
return dotIndex > 0 ? key.substring(0, dotIndex) : key;
},
Collectors.mapping(
Map.Entry::getValue,
Collectors.toList()
)
));
}
// 示例调用
public static void main(String[] args) {
List<string> l1 = List.of("foo", "bar");
List<string> l2 = List.of("goo", "car");
List<string> l3 = List.of("boo", "par");
List<string> l4 = List.of("loo", "tar");
Map<string list>> input = Map.of(
"a.1", l1,
"a.2", l2,
"b.1", l3,
"b.2", l4,
"x.y.z.3", List.of("extra") // 测试多段前缀(取"x.y.z")
);
Map<string list>>> result = groupByPrefix(input);
System.out.println(result);
// 输出:{a=[[foo, bar], [goo, car]], b=[[boo, par], [loo, tar]], x.y.z=[[extra]]}
}
}</string></string></string></string></string></string></string></string></t>
⚠️ 注意事项:
- 若前缀规则非简单首个点号前部分(如 "user.id.01" 需提取 "user"),请自定义前缀提取逻辑(例如正则匹配或 split("\.")[0]);
- groupingBy 默认使用 HashMap,如需有序结果,可传入 TreeMap::new 作为下游收集器的 mapFactory;
- 原始方法中 prefixName(...) 仅返回 Set
,无法完成值聚合,应改用 collect(groupingBy(...)) 范式; - 若最终需要扁平化为单一 List
(如 {"a": [l1, l2] → ["foo","bar","goo","car"]}),可在 mapping 后追加 Collectors.flatMapping(..., toList())(Java 16+)或手动 stream().flatMap(List::stream).collect(toList())。
该方案兼具表达力与扩展性,是处理带命名空间键值对的推荐实践。











