用flatmap递归扁平化多级菜单的核心是将每个菜单项的自身流与递归展开的子树流拼接后压平:stream.concat(stream.of(menu), flattenmenus(menu.getchildren())),从而生成包含所有层级菜单项的一维流。

用 flatMap 对多级菜单做递归扁平化,核心是把“子菜单列表”作为流来处理,并在每一层递归地展开子项,最终合并成一个一维的菜单项流。
理解 flatMap 在树形结构中的作用
flatMap 接收一个函数,该函数对每个元素返回一个 Stream,然后自动将所有子流“压平”成一个流。对于菜单树,每个菜单项可能有 children: List<menu></menu>,我们对每个 Menu 生成两个部分的流:它自己(单元素流),加上它所有后代(递归展开后的流)。
定义菜单数据结构
假设菜单类如下(关键是有 id、name 和可空的 children):
public class Menu {
private Long id;
private String name;
private List<menu> children;
// 构造、getter 省略
}
</menu>
递归 flatMap 扁平化实现
写一个静态方法,接收根菜单列表,返回所有层级的菜单项(含自身)的一维流:
public static Stream<menu> flattenMenus(List<menu> menus) {
if (menus == null || menus.isEmpty()) {
return Stream.empty();
}
return menus.stream()
.flatMap(menu -> Stream.concat(
Stream.of(menu), // 当前节点
flattenMenus(menu.getChildren()) // 递归展开子树
));
}
</menu>
</menu>
说明:
-
Stream.of(menu)把当前菜单转为单元素流,确保它被包含在结果中 -
flattenMenus(menu.getChildren())递归调用,返回子树所有节点的流 -
Stream.concat(a, b)合并当前节点和其后代,避免空指针(若children为null,flattenMenus(null)返回空流)
安全增强版(处理 null children)
更健壮的写法,显式判空子列表:
public static Stream<menu> flattenMenus(List<menu> menus) {
if (menus == null || menus.isEmpty()) return Stream.empty();
return menus.stream()
.flatMap(menu -> {
Stream<menu> self = Stream.of(menu);
Stream<menu> descendants = Optional.ofNullable(menu.getChildren())
.map(MenuUtil::flattenMenus)
.orElse(Stream.empty());
return Stream.concat(self, descendants);
});
}
</menu>
</menu>
</menu>
</menu>
这样即使 menu.getChildren() 是 null,也不会抛异常。
使用示例
调用后可收集为列表、查找、去重或映射字段:
List<menu> allMenus = flattenMenus(rootMenus).collect(Collectors.toList());
// 或只取所有 ID
List<long> allIds = flattenMenus(rootMenus)
.map(Menu::getId)
.collect(Collectors.toList());
</long>
</menu>
不复杂但容易忽略细节。关键是把“当前节点 + 子树展开”看作两个流的拼接,再用 flatMap 自动扁平化整棵树。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











