标题:Java 中使用 Stream 和递归 Map 实现嵌套字符串的层级分组

发布时间 - 2026-01-28 00:00:00    点击率:

本文介绍如何将形如 "caso.id"、"caso.responsavel.dadospessoais.nome" 的点分隔字符串列表,递归构建为嵌套的 `map` 结构,实现真正的多级分组与树状打印,适用于动态字段建模、json schema 生成等场景。

在 Java 中,对点号(.)分隔的路径字符串进行层级化组织是常见需求,例如映射 DTO 字段路径、构建动态查询条件树或生成嵌套配置结构。Collectors.groupingBy() 虽强大,但仅支持单层分组;而本例需递归解析路径深度、动态创建嵌套 Map,无法通过标准 Stream 操作一步完成——必须结合递归逻辑与泛型 Map 构建。

核心思路是:将每个字符串按 . 拆分为路径节点数组(如 "caso.responsavel.dadosPessoais.nome" → ["caso", "responsavel", "dadosPessoais", "nome"]),再逐层下沉插入到嵌套 Map 中。其中 Object 类型可容纳两种值:

  • 叶子节点(最后一级)→ 实际无值,仅作占位(或可存 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 + " "); } } } }

输出效果(缩进清晰体现层级关系):

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 环境下完成灵活、可读、可扩展的嵌套结构构建。


# java  # js  # json  # node  # ai  # stream  # red  # String  # Boolean  # Object  # NULL  # if  # 封装  # Filter  # 字符串  # 递归  # Length  # 泛型  # map  # 并发  # 树状  # 本例  # 两种  # 两次  # 适用于  # 可在  # 不存在  # 自定义  # 如需 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Laravel如何使用Vite进行前端资源打包?(配置示例)  Android自定义控件实现温度旋转按钮效果  如何快速上传建站程序避免常见错误?  手机怎么制作网站教程步骤,手机怎么做自己的网页链接?  UC浏览器如何切换小说阅读源_UC浏览器阅读源切换【方法】  如何在云虚拟主机上快速搭建个人网站?  百度输入法全感官ai怎么关 百度输入法全感官皮肤关闭  车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?  怎样使用JSON进行数据交换_它有什么限制  如何彻底删除建站之星生成的Banner?  佐糖AI抠图怎样调整抠图精度_佐糖AI精度调整与放大细化操作【攻略】  济南网站建设制作公司,室内设计网站一般都有哪些功能?  专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?  Laravel中的Facade(门面)到底是什么原理  黑客如何通过漏洞一步步攻陷网站服务器?  如何用花生壳三步快速搭建专属网站?  Windows Hello人脸识别突然无法使用  Laravel Docker环境搭建教程_Laravel Sail使用指南  Laravel怎么连接多个数据库_Laravel多数据库连接配置  Laravel如何集成微信支付SDK_Laravel使用yansongda-pay实现扫码支付【实战】  Laravel Octane如何提升性能_使用Laravel Octane加速你的应用  海南网站制作公司有哪些,海口网是哪家的?  图册素材网站设计制作软件,图册的导出方式有几种?  Bootstrap CSS布局之列表  Laravel如何处理文件下载请求?(Response示例)  如何在建站之星绑定自定义域名?  深圳防火门网站制作公司,深圳中天明防火门怎么编码?  Laravel Livewire是什么_使用Laravel Livewire构建动态前端界面  大学网站设计制作软件有哪些,如何将网站制作成自己app?  制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?  香港服务器部署网站为何提示未备案?  JavaScript Ajax实现异步通信  如何快速搭建安全的FTP站点?  Laravel数据库迁移怎么用_Laravel Migration管理数据库结构的正确姿势  Laravel如何记录自定义日志?(Log频道配置)  Laravel如何优雅地处理服务层_在Laravel中使用Service层和Repository层  微信小程序制作网站有哪些,微信小程序需要做网站吗?  Laravel如何设置自定义的日志文件名_Laravel根据日期或用户ID生成动态日志【技巧】  HTML 中动态设置元素 name 属性的正确语法详解  laravel怎么为应用开启和关闭维护模式_laravel应用维护模式开启与关闭方法  Laravel的HTTP客户端怎么用_Laravel HTTP Client发起API请求教程  Laravel如何使用Passport实现OAuth2?(完整配置步骤)  Laravel如何创建自定义Artisan命令?(代码示例)  Laravel怎么在Controller之外的地方验证数据  Laravel怎么设置路由分组Prefix_Laravel多级路由嵌套与命名空间隔离【步骤】  Laravel怎么上传文件_Laravel图片上传及存储配置  Laravel怎么做数据加密_Laravel内置Crypt门面的加密与解密功能  Laravel如何实现RSS订阅源功能_Laravel动态生成网站XML格式订阅内容【教程】  Laravel怎么进行数据库事务处理_Laravel DB Facade事务操作确保数据一致性  悟空识字如何进行跟读录音_悟空识字开启麦克风权限与录音