17370845950

标题:Java Stream 实现嵌套字符串的递归分组(模拟树形结构映射)

本文介绍如何使用 java 递归 + hashmap 构建嵌套层级结构,将点号分隔的字符串(如 "caso.responsavel.dadospessoais.nome")自动解析并组织为多级 map 树,支持任意深度嵌套,适用于动态字段路径建模场景。

在 Java 中,Collectors.groupingBy() 虽强大,但仅适用于单层分组;而面对类似 "caso.competencia.nome" 这类含多级路径的字符串,需构建树状嵌套映射(Tree-like Map),即每个节点既是键,又可作为子 Map 的容器。这无法通过标准 Stream API 直接完成,但可通过递归填充 + 泛型 Map 嵌套优雅实现。

核心思路

将每个字符串按 . 拆分为路径数组(如 "caso.responsavel.dadosPessoais.nome" → ["caso", "responsavel", "dadosPessoais", "nome"]),再逐级下沉插入到嵌套 Map 中:

  • Object 类型允许值为 String(叶子节点)或 Map(中间节点);
  • 递归函数 fill() 负责从指定层级开始,确保路径上每级键存在且为 Map,最终在末尾插入占位(实际业务中可替换为真实值);
  • print() 函数则以缩进形式可视化树结构,便于调试。

完整可运行示例

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);
        }

        System.out.println("Nested structure:");
        pr

int(root, ""); } // 递归填充:将 nodes[i..end] 路径插入到 map 中 public static void fill(Map map, String[] nodes, int i) { if (i >= nodes.length) return; String key = nodes[i]; Object existing = map.get(key); if (existing == null) { // 当前层级不存在 → 创建新子 Map 并挂载 Map subMap = new HashMap<>(); map.put(key, subMap); fill(subMap, nodes, i + 1); // 继续向下构建 } else if (existing instanceof Map) { // 已存在子 Map → 继续递归填充 @SuppressWarnings("unchecked") Map subMap = (Map) existing; fill(subMap, nodes, i + 1); } // 若 existing 非 Map(如已存为 String),此处可抛异常或覆盖逻辑(本例仅建结构,无需值) } // 递归打印:缩进显示层级关系 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 + " "); } } } }

关键注意事项

  • 类型安全提示:Map 是必要妥协,实际项目中建议封装为 NestedPathMap 类,隐藏强制转换细节;
  • ⚠️ 叶子节点无值:当前实现仅构建结构(所有叶子为 null 或空 Map)。若需存储原始字符串或关联数据,可在 i == nodes.length - 1 时 map.put(key, path);
  • ? 避免重复路径:若输入含重复路径(如两次 "caso.id"),第二次 fill() 将静默跳过 —— 可根据需求改为抛异常或计数;
  • ? 扩展性:该模式可轻松适配 JSON Schema 生成、动态表单字段分组、权限路径树等场景。

总结

虽然 Java Stream 不直接支持“递归 groupingBy”,但结合 split()、HashMap 和简洁递归,我们能以不到 30 行核心逻辑实现任意深度的嵌套字符串分组。它不依赖第三方库,语义清晰,且易于单元测试与定制 —— 是处理动态路径建模的经典轻量方案。