详解如何使用Java流API构建树形结构数据

 更新时间:2024年04月02日 16:20:33   作者:大阳光男孩  
在实际开发中,构建树状层次结构是常见需求,本文主要为大家详细介绍了如何使用Java 8 Stream API将扁平化的菜单数据转换为具有层级关系的树形结构,需要的可以参考下

简介

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

1. 核心类定义 - Menu

@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>:一个仅包含顶级菜单项的列表,每个顶级菜单项已填充了其下级子菜单。

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. 辅助方法——获取指定菜单的所有子菜单

 /**
     * 获取指定菜单的所有子菜单。
     *
     * @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()); // 收集结果,生成列表
    }

4. 示例数据生成方法 —— menusData()

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)

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对菜单数据进行处理,首先筛选出顶级菜单项,并通过递归方式为其添加子菜单。最后,得到了一个完整的树形菜单结构。 

到此这篇关于详解如何使用Java流API构建树形结构数据的文章就介绍到这了,更多相关Java流构建树形结构数据内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java的Spring框架中DAO数据访问对象的使用示例

    Java的Spring框架中DAO数据访问对象的使用示例

    这篇文章主要介绍了Java的Spring框架中DAO数据访问对象的使用示例,分为在Spring中DOA与JDBC以及与Hibernate的配合使用两种情况来进行演示,需要的朋友可以参考下
    2016-03-03
  • Spring Controller接收前端JSON数据请求方式

    Spring Controller接收前端JSON数据请求方式

    这篇文章主要为大家介绍了Spring Controller接收前端JSON数据请求方式详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07
  • 详解SpringCloud的负载均衡

    详解SpringCloud的负载均衡

    这篇文章主要介绍了SpringCloud的负载均衡的相关资料,帮助大家更好的理解和学习使用SpringCloud,感兴趣的朋友可以了解下
    2021-03-03
  • springboot整合shiro实现记住我功能

    springboot整合shiro实现记住我功能

    这篇文章主要介绍了springboot整合shiro实现记住我功能,配置类 ShiroConfig,通过实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2021-10-10
  • Ubuntu安装jenkins完成自动化构建详细步骤

    Ubuntu安装jenkins完成自动化构建详细步骤

    Jenkins是一个开源的自动化服务器,可以用来轻松地建立持续集成和持续交付(CI/CD)管道,这篇文章主要给大家介绍了关于Ubuntu安装jenkins完成自动化构建的相关资料,需要的朋友可以参考下
    2024-03-03
  • 关于jar包与war包的区别及说明

    关于jar包与war包的区别及说明

    这篇文章主要介绍了关于jar包与war包的区别及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • 如何解决org.apache.jasper.JasperException:无法为JSP编译类详解

    如何解决org.apache.jasper.JasperException:无法为JSP编译类详解

    这篇文章主要给大家介绍了关于如何解决org.apache.jasper.JasperException:无法为JSP编译类的相关资料,原因可能是JSP文件的语法错误、类路径问题或其他配置问题,建议检查JSP文件的语法、类路径配置和其他相关配置,需要的朋友可以参考下
    2023-06-06
  • Java super关键字调用父类过程解析

    Java super关键字调用父类过程解析

    这篇文章主要介绍了Java super关键字调用父类过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • java开源调度如何给xxljob加k8s执行器

    java开源调度如何给xxljob加k8s执行器

    这篇文章主要介绍了java开源调度如何给xxljob加一个k8s执行器, xxljob 在设计上,抽象出了执行器的接口,所以实现一个语言的执行器并不复杂,这里主要探索下,如何利用k8s的pod 的能力,使用 xxljob 调度 pod 运行,实现一个通用的和语言无关的执行器
    2022-02-02
  • SpringBoot如何使用RateLimiter通过AOP方式进行限流

    SpringBoot如何使用RateLimiter通过AOP方式进行限流

    这篇文章主要介绍了SpringBoot如何使用RateLimiter通过AOP方式进行限流,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06

最新评论