当前位置: 首页 > news >正文

Java Stream 高级应用:优雅地扁平化(FlatMap)递归树形结构数据

💡 Java Stream 高级应用:优雅地扁平化(FlatMap)递归树形结构数据

在 Java 开发中,处理具有层级关系的 树形结构数据是常见的需求,例如组织架构、文件目录或多级菜单。如何将这种带有 children 列表的递归结构完全扁平化(Flatten),并用现代化的 Java Stream API 进行处理,是一个高效且优雅的解决方案。

本文将通过一个清晰的 “部门(Department)” 示例,演示如何利用 flatMap
和匿名递归函数, 在纯 Java Stream 中实现复杂的树形结构扁平化。


🏢 示例结构:部门(Department)类

首先,定义我们的树形结构类 Department

import java.util.List;public class Department {private final long id;private final String name;/** 子部门列表 */private List<Department> children;// 构造器和Getter...public long getId() { return id; }public List<Department> getChildren() { return children; }// ...
}

我们的目标是:

给定一个顶级部门列表 List<Department>,最终获取
所有部门(包括所有子孙) 的 ID 列表 List<Long>


🧠 核心技巧:Stream 内部的递归 FlatMap

在 Stream 中,flatMap 用于将 Stream 中的元素转换为新的 Stream
并连接起来。要实现递归扁平化,关键在于:

  1. 利用 匿名内部类 (new Function<...>()) 来实现 java.util.function.Function 接口;
  2. apply 方法内部,通过 this::apply 实现对自身的递归调用;
  3. 使用 Stream.concat() 将当前节点和所有子孙节点的 Stream 拼接起来。

我们将展示两种基于此核心技巧的实现方式。


✅ 写法一:使用局部 Function 变量(推荐)

这种方式将递归逻辑提取到一个局部变量中,使主 Stream 流程保持简洁清晰。

import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;// 假设这是我们的顶级部门列表
List<Department> topLevelDepartments = createSampleDepartments(); // 1️⃣ 定义一个局部匿名 Function 变量,用于实现递归扁平化
Function<Department, Stream<Department>> flatMapRecursive = new Function<Department, Stream<Department>>() {@Overridepublic Stream<Department> apply(Department dept) {// 自身的 StreamStream<Department> selfStream = Stream.of(dept);// 子集的 Stream:递归调用 apply 并 flatMap 展平Stream<Department> childrenStream = (dept.getChildren() != null && !dept.getChildren().isEmpty()) ? dept.getChildren().stream().flatMap(this::apply) // ★ 递归自调用: Stream.empty(); // 合并自身和子集的 Streamreturn Stream.concat(selfStream, childrenStream);}};// 2️⃣ Stream 主流程:扁平化并提取 ID
List<Long> allDepartmentIds = topLevelDepartments.stream()// 使用定义的递归函数进行扁平化.flatMap(flatMapRecursive) // 3️⃣ 提取所有部门的 ID.map(Department::getId)// 4️⃣ 收集结果.collect(Collectors.toList());

优点:

  • ✅ 可读性高:主 Stream 流程非常简洁;
  • ✅结构清晰:递归逻辑被封装在一个命名变量中;
  • ✅实用性强:推荐在日常开发中使用。

✨ 写法二:直接嵌入 flatMap 匿名类

这种方式将递归逻辑直接作为参数嵌入到 flatMap中,实现了"完全在一个流里解决"的效果。

import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;// 假设这是我们的顶级部门列表
List<Department> topLevelDepartments = createSampleDepartments(); List<Long> allDepartmentIds = topLevelDepartments.stream()// 关键步骤:直接在 flatMap 中定义并实现递归函数.flatMap(new Function<Department, Stream<Department>>() {@Overridepublic Stream<Department> apply(Department dept) {Stream<Department> selfStream = Stream.of(dept);Stream<Department> childrenStream = (dept.getChildren() != null && !dept.getChildren().isEmpty()) ? dept.getChildren().stream().flatMap(this::apply) // ★ 递归自调用: Stream.empty(); return Stream.concat(selfStream, childrenStream);}})// 提取所有部门的 ID.map(Department::getId)// 收集结果.collect(Collectors.toList());

优点:

  • ✅ 代码紧凑:避免了额外的局部变量定义;
  • ✅ 满足纯 Stream要求:实现了"一条链解决所有问题";

缺点:

  • ⚠️ 可读性较低:flatMap 内部代码块较长;
  • ⚠️逻辑嵌套深,不易复用。

📊 总结对比

写法一:局部变量 Function写法二:嵌入匿名类
主流程可读性✅ 高(推荐)❌ 低(代码块长)
递归逻辑封装✅ 独立命名变量❌ 内嵌逻辑,不易重用
可维护性✅ 强⚠️ 弱
应用场景推荐在所有项目中使用适用于行数要求严格的场景

🏁 总结

无论采用哪种写法,核心思路都是通过:

匿名内部类 + Stream.concat() + this::apply 实现递归扁平化

这种方式不仅优雅,而且能充分利用 Stream 的惰性特性与函数式编程风格。


✅ 推荐实践:
在日常开发中,建议使用 “写法一” 既优雅又清晰,是现代 Java 处理树形结构的最佳实践之一。

http://www.dtcms.com/a/507020.html

相关文章:

  • git推送本地仓库到远程 以及 模拟多人协作
  • 【开题答辩实录分享】以《预约上门维修服务运营与数据分析系统的设计与实现》为例进行答辩实录分享
  • 数据结构7:栈和队列
  • SpringBoot的启动流程原理——小白的魔法引擎探秘
  • Vue3 + Element Plus 弹框树形结构首次打开不更新问题排查与解决
  • 我先做个网站怎么做网络推广技术外包
  • 互联网公司排名前十名名单seo整站优化更能准确获得客户
  • 网络运维学习笔记
  • Helm、HPA 与 Rancher:Kubernetes(十) 生态核心工具详解
  • Docker常见问题
  • 拟合优度:模型与数据的契合之度
  • 理解 Python 的有序字典 OrderedDict
  • 狙击生态的演化史:从抢跑到模型套利
  • 用C语言实现外观模式
  • Git三路合并算法的弊端
  • 网站模板文件扫描工作招聘58同城
  • 网站建设上线问题企业网站的推广方法有哪些
  • LeetCode:207. 课程表
  • Oracle EBS ERP开发——报表生成Excel标准模板设计
  • CANoe基础讲解02:掌握CANoe Trace窗口
  • Kanass V1.3.3版本发布,支持在线安装与消息配置
  • 第十七篇:本地模型部署:使用DeepSeek开源模型进行离线推理
  • 【STM32项目开源】基于STM32的智能家居环境监测系统
  • 串口AT指令控制EC20连接MQTT服务器
  • 如何实现企业网站推广的系统性网站建设腾讯课堂
  • 全网营销型的网站wordpress 开源吗
  • 常见Linux环境变量深度解析
  • Jetson上安装TensorRT
  • 开发避坑指南(62):解决URLDecoder:Illegal hex characters in escape (%) pattern 异常
  • DAX分列年月日