使用Java流API构建树形结构数据

简介:

在实际开发中,构建树状层次结构是常见需求,如组织架构、目录结构或菜单系统。本教案通过解析给定的Java代码,展示如何使用Java 8 Stream API将扁平化的菜单数据转换为具有层级关系的树形结构。

java 复制代码
@Data
@NoArgsConstructor
@AllArgsConstructor
static class Menu {
    private Long id;
    private String name;
    private Long parentId;
    private List<Menu> children;
}

提示:此处定义了一个名为Menu的类,它包含了菜单项的基本属性,包括ID、名称、父菜单ID以及一个用于存储子菜单项的列表。

2. main方法解析及实现功能

输入参数:

  • List<Menu> menus:包含所有菜单项的集合。

输出结果:

  • List<Menu>:一个仅包含顶级菜单项的列表,每个顶级菜单项已填充了其下级子菜单。
java 复制代码
public static void main(String[] args) {
        List<Menu> menus = menusData();
        /**
         * 从菜单列表中筛选出顶级菜单,并为其添加子菜单。
         *
         * @param menus 菜单列表,包含所有菜单项。
         * @return 包含所有顶级菜单的列表,其中每个顶级菜单均已包含其所有子菜单。
         */
        List<Menu> topLevelMenus = menus.stream() // 使用流处理menus集合
                        .filter(menu -> menu.getParentId() == 0 || menus.stream().noneMatch(other -> other.getId().equals(menu.getParentId()))) // 筛选条件:父菜单ID为0或不存在对应父菜单的菜单项
                        .peek(menu -> menu.setChildren(getChildren(menu, menus))) // 为每个顶级菜单设置子菜单
                        .collect(Collectors.toList()); // 将筛选后的顶级菜单集合转换为List(Menu)类型
    }

3. 辅助方法------获取指定菜单的所有子菜单

java 复制代码
 /**
     * 获取指定菜单的所有子菜单。
     *
     * @param menu 指定的菜单对象,我们要查找它的子菜单。
     * @param menus 所有菜单的列表,从中筛选出子菜单。
     * @return 返回一个包含指定菜单所有子菜单的列表。这个列表中的每个菜单对象都可能包含它们自己的子菜单列表。
     */
    private static List<Menu> getChildren(Menu menu, List<Menu> menus) {
        // 使用流对菜单列表进行处理,筛选出指定菜单的子菜单
        return menus.stream()
                .filter(child -> child.getParentId().equals(menu.getId())) // 筛选条件:菜单的父菜单ID与指定菜单ID匹配
                .peek(child -> child.setChildren(getChildren(child, menus))) // 递归设置每个子菜单的子菜单列表
                .collect(Collectors.toList()); // 收集结果,生成列表
    }
java 复制代码
private static List<Menu> menusData() {
    return Arrays.asList(
            new Menu(1L, "一级菜单1", 0L, null),
            new Menu(2L, "二级菜单1", 1L, null),
            new Menu(3L, "三级菜单1", 2L, null),
            new Menu(4L, "一级菜单2", 0L, null),
            new Menu(5L, "二级菜单2", 4L, null),
            new Menu(6L, "一级菜单3", 0L, null)
    );
}

5.完整代码,以及演示(TreeExample.java)

java 复制代码
package com.tenement.auto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class TreeExample {

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    static
    class Menu {
        private Long id;
        private String name;
        private Long parentId;

        private List<Menu> children;
    }

    public static void main(String[] args) {
        List<Menu> menus = menusData();
        /**
         * 从菜单列表中筛选出顶级菜单,并为其添加子菜单。
         *
         * @param menus 菜单列表,包含所有菜单项。
         * @return 包含所有顶级菜单的列表,其中每个顶级菜单均已包含其所有子菜单。
         */
        List<Menu> topLevelMenus = menus.stream() // 使用流处理menus集合
                        .filter(menu -> menu.getParentId() == 0 || menus.stream().noneMatch(other -> other.getId().equals(menu.getParentId()))) // 筛选条件:父菜单ID为0或不存在对应父菜单的菜单项
                        .peek(menu -> menu.setChildren(getChildren(menu, menus))) // 为每个顶级菜单设置子菜单
                        .collect(Collectors.toList()); // 将筛选后的顶级菜单集合转换为List(Menu)类型
    }

    /**
     * 获取指定菜单的所有子菜单。
     *
     * @param menu 指定的菜单对象,我们要查找它的子菜单。
     * @param menus 所有菜单的列表,从中筛选出子菜单。
     * @return 返回一个包含指定菜单所有子菜单的列表。这个列表中的每个菜单对象都可能包含它们自己的子菜单列表。
     */
    private static List<Menu> getChildren(Menu menu, List<Menu> menus) {
        // 使用流对菜单列表进行处理,筛选出指定菜单的子菜单
        return menus.stream()
                .filter(child -> child.getParentId().equals(menu.getId())) // 筛选条件:菜单的父菜单ID与指定菜单ID匹配
                .peek(child -> child.setChildren(getChildren(child, menus))) // 递归设置每个子菜单的子菜单列表
                .collect(Collectors.toList()); // 收集结果,生成列表
    }

    private static List<Menu> menusData() {
        return Arrays.asList(
                new Menu(1L, "一级菜单1", 0L,null),
                new Menu(2L, "二级菜单1", 1L,null),
                new Menu(3L, "三级菜单1", 2L,null),
                new Menu(4L, "一级菜单2", 0L,null),
                new Menu(5L, "二级菜单2", 4L,null),
                new Menu(6L, "一级菜单3", 0L,null)
        );
    }

}

总结:该案例展示了如何利用Java 的Stream API对菜单数据进行处理,首先筛选出顶级菜单项,并通过递归方式为其添加子菜单。最后,得到了一个完整的树形菜单结构。

相关推荐
yufei-coder2 分钟前
C#基础语法
开发语言·c#·.net
数据龙傲天2 分钟前
1688商品API接口:电商数据自动化的新引擎
java·大数据·sql·mysql
长天一色2 分钟前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript
_.Switch14 分钟前
Python机器学习模型的部署与维护:版本管理、监控与更新策略
开发语言·人工智能·python·算法·机器学习
醉颜凉16 分钟前
银河麒麟桌面操作系统修改默认Shell为Bash
运维·服务器·开发语言·bash·kylin·国产化·银河麒麟操作系统
NiNg_1_23422 分钟前
Vue3 Pinia持久化存储
开发语言·javascript·ecmascript
带带老表学爬虫31 分钟前
java数据类型转换和注释
java·开发语言
qianbo_insist33 分钟前
simple c++ 无锁队列
开发语言·c++
千里码aicood38 分钟前
【2025】springboot教学评价管理系统(源码+文档+调试+答疑)
java·spring boot·后端·教学管理系统
BigYe程普44 分钟前
我开发了一个出海全栈SaaS工具,还写了一套全栈开发教程
开发语言·前端·chrome·chatgpt·reactjs·个人开发