
本文介绍如何使用 java stream api 将键含公共前缀(如 "a.1", "a.2")的 map 按前缀提取、分组,并将对应的所有值列表聚合为嵌套列表结构。
本文介绍如何使用 java stream api 将键含公共前缀(如 "a.1", "a.2")的 map 按前缀提取、分组,并将对应的所有值列表聚合为嵌套列表结构。
在实际开发中,常遇到类似场景:原始 Map
核心思路是:
- 从每个 Map.Entry 中提取键的前缀(本例中用 substring(0, 1) 获取首字符;生产环境建议使用更健壮的方式,如 key.split("\.")[0] 或正则匹配);
- 将该前缀作为分组 key;
- 同时将 entry 的 value(即原 List
)映射后收集为 List - >。
以下是完整可运行示例(基于 Java 14+):
import java.util.*;
import java.util.stream.Collectors;
public class PrefixGrouping {
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
);
// 按前缀分组:提取 key 的前缀(此处为第一个字符),并将 value 收集为 List<list>>
Map<string list>>> grouped = input.entrySet().stream()
.collect(Collectors.groupingBy(
entry -> entry.getKey().split("\.")[0], // 更鲁棒的前缀提取
Collectors.mapping(Map.Entry::getValue, Collectors.toList())
));
System.out.println(grouped);
// 输出: {a=[[foo, bar], [goo, car]], b=[[boo, par], [loo, tar]]}
}
}</string></list></string></string></string></string></string>
⚠️ 注意事项:
- 前缀提取需适配实际格式:若前缀长度不固定(如 "user.profile", "admin.permissions"),请避免硬编码 substring(0,1),改用 split("\.") 或正则 Pattern.compile("^([^\.]+)\.").matcher(key).replaceAll("$1");
- 空键/非法格式防护:生产代码中应增加 Objects.nonNull(entry.getKey()) 和 !entry.getKey().isEmpty() 判断,防止 NullPointerException 或 StringIndexOutOfBoundsException;
-
值类型一致性:确保所有 value 均为 List
类型,否则 mapping(..., toList()) 可能引发 ClassCastException; - 并发安全需求:若源 Map 可能被并发修改,请先通过 Collections.unmodifiableMap() 或 ConcurrentHashMap 构建安全视图。
总结:借助 groupingBy 与 mapping 的组合,我们无需手动遍历或维护临时集合,即可高效、声明式地完成前缀分组任务。该方案兼具可读性、扩展性与函数式编程优势,是处理此类键值归类问题的推荐实践。











