本文介绍一种基于 java 8 stream 的简洁、函数式方法,实现对树形结构对象(如嵌套的 message 实例)进行深度优先递归遍历,并将其全部节点收集为扁平化列表。
本文介绍一种基于 java 8 stream 的简洁、函数式方法,实现对树形结构对象(如嵌套的 message 实例)进行深度优先递归遍历,并将其全部节点收集为扁平化列表。
在处理具有自引用嵌套关系的对象(例如树形结构)时,常见的需求是“获取当前节点及其所有后代节点”。以 Message 类为例,其包含 List<Message> children 字段,形成典型的递归树结构。手动编写深度优先遍历(DFS)虽可行,但易出错且不易复用;而借助 Java Stream API 可写出更清晰、不可变、声明式的解决方案。
✅ 推荐实现:递归 Stream 方法
在 Message 类中添加如下 children() 方法:
public Stream<Message> children() {
Stream<Message> result = Stream.of(this);
if (children != null && !children.isEmpty()) {
result = Stream.concat(result,
children.stream().flatMap(Message::children));
}
return result;
}? 说明:
- Stream.of(this) 将当前节点作为流的首个元素;
- children.stream().flatMap(Message::children) 对每个子节点递归调用 children(),并将返回的多个子流“扁平化”合并;
- Stream.concat() 合并当前节点与所有后代节点流,保证根节点始终位于结果最前(前序遍历顺序)。
? 使用示例
假设已构建如下树形结构:
立即学习“Java免费学习笔记(深入)”;
Message root = new Message(1, "ROOT"); Message child1 = new Message(2, "CHILD1"); Message grandChild = new Message(3, "GRANDCHILD"); child1.setChildren(List.of(grandChild)); root.setChildren(List.of(child1, new Message(4, "CHILD2")));
调用即可获得包含全部 4 个节点的扁平列表:
List<Message> allNodes = root.children().collect(Collectors.toList()); System.out.println(allNodes.size()); // 输出: 4
⚠️ 注意事项与最佳实践
- 空安全:示例中增加了 !children.isEmpty() 判断,避免对 null 或空集合执行 stream()(亦可统一用 Objects.requireNonNullElse(children, List.of()) 预处理);
- 性能考量:该方案适用于中等规模树(千级节点内),因每次递归都会新建 Stream 实例;超大规模场景建议改用迭代式 DFS(栈模拟)或考虑 Stream.iterate + 状态管理;
- 不可变性保障:Stream 是惰性求值的,children() 方法不修改原对象,符合函数式编程原则;
- 扩展性:若需广度优先(BFS),应改用队列迭代实现,Stream 本身不天然支持 BFS;
- 泛型增强(进阶):可将逻辑抽象为通用接口 TreeNode<T>,配合 Function<T, List<T>> getChildrenFn 实现跨类型复用。
✅ 总结
通过一个轻量级的递归 Stream 方法,我们以不到 10 行核心代码,优雅地解决了树形对象的全量扁平化遍历问题。它兼具可读性、可组合性(可链式调用 filter()/map() 等)与工程健壮性,是现代 Java 处理嵌套结构的推荐范式之一。










