
本文介绍如何将形如 "caso.id"、"caso.responsavel.dadospessoais.nome" 的点分隔字符串列表,递归构建为嵌套的 `map
在 Java 中,对点号(.)分隔的路径字符串进行层级化组织是常见需求,例如映射 DTO 字段路径、构建动态查询条件树或生成嵌套配置结构。Collectors.groupingBy() 虽强大,但仅支持单层分组;而本例需递归解析路径深度、动态创建嵌套 Map,无法通过标准 Stream 操作一步完成——必须结合递归逻辑与泛型 Map 构建。
核心思路是:将每个字符串按 . 拆分为路径节点数组(如 "caso.responsavel.dadosPessoais.nome" → ["caso", "responsavel", "dadosPessoais", "nome"]),再逐层下沉插入到嵌套 Map
- 叶子节点(最后一级)→ 实际无值,仅作占位(或可存 null/Boolean.TRUE 表示存在);
- 中间节点 → 指向子 Map
。
以下是完整可运行实现:
import java.util.*;
public class NestedStringGrouping {
public static void main(String[] args) {
String[] array = {
"caso.id",
"caso.unidadeDoCaso.id",
"caso.etiqueta",
"caso.sigiloso",
"caso.idPecaSegredoJustica",
"caso.numeroAno",
"caso.numero",
"caso.competencia.id",
"caso.competencia.ativo",
"caso.competencia.nome",
"caso.responsavel.id",
"caso.responsavel.dadosPessoais.nome",
"caso.escrivao.id",
"caso.escrivao.dadosPessoais.nome"
};
Map root = new HashMap<>();
for (String path : array) {
String[] nodes = path.split("\\.");
fill(root, nodes, 0);
}
print(root, "");
}
/**
* 递归填充嵌套 Map:从 index 开始,将 nodes[index..end] 插入到 map 中
*/
public static void fill(Map map, String[] nodes, int index) {
if (index >= nodes.length) return;
String key = nodes[index];
Object existing = map.get(key);
if (existing == null) {
// 当前层级不存在 → 创建新子 Map 并挂载
Map childMap = new HashMap<>();
map.put(key, childMap);
fill(childMap, nodes, index + 1); // 继续向下构建
} else if (existing instanceof Map) {
// 已存在子 Map → 递归插入到该子 Map
@SuppressWarnings("unchecked")
Map childMap = (Map) existing;
fill(childMap, nodes, index + 1);
}
// 若 existing 非 Map(如意外覆盖),此处可抛异常或忽略(本例中不会发生)
}
/**
* 树状打印 Map,缩进表示层级深度
*/
public static void print(Map map, String indent) {
for (String key : map.keySet()) {
System.out.println(indent + key);
Object value = map.get(key);
if (value instanceof Map) {
print((Map) value, indent + " ");
}
}
}
} ✅ 输出效果(缩进清晰体现层级关系):
立即学习“Java免费学习笔记(深入)”;
caso
id
unidadeDoCaso
id
etiqueta
sigiloso
idPecaSegredoJustica
numeroAno
numero
competencia
id
ativo
nome
responsavel
id
dadosPessoais
nome
escrivao
id
dadosPessoais
nome⚠️ 注意事项:
-
类型安全:Map
是运行时泛型擦除后的折中方案;若需编译期强约束,可封装为 NestedPathTree 自定义类,提供 add(String path) 和 getChildren(String... ancestors) 等方法。 - 重复路径处理:当前 fill() 对重复路径(如两次 "caso.id")静默忽略,如需校验可添加 if (index == nodes.length - 1 && existing != null) 报警逻辑。
- 空节点防御:生产环境建议在 split() 后过滤空字符串(Arrays.stream(nodes).filter(s -> !s.isBlank()).toArray(String[]::new)),避免 "a..b" 导致异常。
- 性能考量:对于超大规模路径集(>10 万条),可考虑用 Trie 或 ConcurrentHashMap 优化并发插入,但本方案已满足绝大多数元数据建模场景。
该模式本质是轻量级路径字典树(Path Trie)的 Map 实现,无需引入额外依赖,即可在纯 JDK 环境下完成灵活、可读、可扩展的嵌套结构构建。










