开发小技巧系列 - Java实现树形结构的方式有那些?

简介: 用java代码如何转一个列表的数据,转换成一个树形结构的数据,记录一下,可以帮助一般的开发者

开发小技巧系列文章,是本人对过往平台系统的设计开发及踩坑的记录与总结,给初入平台系统开发的开发人员提供参考与帮助。

在开发的过程中,有时候需要将集合的数据转换成一个树形结构,比如功能菜单、组织机构、或者商品分类等的场景。一般这些数据在数据表的存储中,都是采用行的方式来存储数据,方便对数据进行管理,在表的字段上会有“父ID(parent_id)”的字段,来表示关系。

假设有如下表结构及数据:

image.png

需要转换成一个树形结构,预期结构:

image.png

如何用java程序来实现呢?可能很多人会想到用递归来实现,这也是最常见的方式,可以实现一棵无限级的树形结果。是否还有其他实现方式呢?让我们先从递归实现来说起。
首先,需要定义一个树形结构的对象,如下:TreeVo.java

package net.jhelp.demo.tree;
import lombok.Data;
import java.util.List;
/** 
* 
* 
* @author : kame 
* @date: 2022/4/9 10:30 AM 
*/
@Data
public class TreeVo {
   
   
    private Integer id;
    private String name;
    private List<TreeVo> nodeList;
    public TreeVo(Integer id, String name) {
   
   
        this.id = id;
        this.name = name; 
   }
}

树形转换工具类 TreeKit.java , 递归函数的实现:

/**
     * list集合的行数据,转换成 tree 结构
     * @param beans
     * @return
     */    
public static List<TreeVo> list2Tree(List<Table> beans) {
   
   
        List<TreeVo> result = new ArrayList<>();
        if(!CollectionUtils.isEmpty(beans)){
   
   
            for(Table p : beans){
   
   
                if(p.getParentId() == null || p.getParentId() == 0) {
   
   
                    TreeVo vo = new TreeVo(p.getId(),p.getName());
                    vo.setNodeList(recurrence(beans, p));
                    result.add(vo);
                }
            } 
       }
       return result;
    }    /**
     *  递归函数
     * @param list
     * @param vo
     */
    private static List<TreeVo> recurrence(List<Table> list, Table vo){
   
   
        List<TreeVo> subNodes = new ArrayList<>();
        for(Table d : list){
   
   
            if (vo.getId().equals(d.getParentId())) {
   
   
                TreeVo sub = new TreeVo(d.getId(), d.getName());
                sub.setNodeList(recurrence(list, d));
                subNodes.add(sub);
            }
        } 
       return subNodes;
    }

测试用例:

    //模拟数据库查询出来的结果
    public static
            List<Table> tableData = Arrays.asList(
            new Table(1, 0, "根节点"),
            new Table(2, 1, "子节点1"),
            new Table(3, 2, "子节点1.1"), 
           new Table(4, 2, "子节点1.2"),
            new Table(5, 2, "子节点1.3"),
            new Table(6, 1, "子节点2"),
            new Table(7, 6, "子节点2.1"),
            new Table(8, 6, "子节点2.2"),
            new Table(9, 1, "子节点3"), 
           new Table(10, 9, "子节点3.1")
    );   

    @Test
    public void Bo2TreeTest(){
   
   
        List<TreeVo> result = TreeKit.list2Tree(tableData);
        log.info("递归:转换结果:{}", JsonUtil.toJson(result));
    }

执行结果为:

css复制代码[    {
   
           "id":1,        "name":"根节点",        "nodeList":[            {
   
                   "id":2,                "name":"子节点1",                "nodeList":[                    {
   
                           "id":3,                        "name":"子节点1.1",                        "nodeList":[                        ]
                    },
                    {
   
    
                       "id":4,
                        "name":"子节点1.2",
                        "nodeList":[
                        ]
                    },
                    {
   
   
                        "id":5,
                        "name":"子节点1.3",
                        "nodeList":[
                        ]
                    }
                ]
            },
            {
   
   
                "id":6,
                "name":"子节点2",
                "nodeList":[
                    {
   
   
                        "id":7,
                        "name":"子节点2.1",
                        "nodeList":[                        ]
                    },
                    {
   
   
                        "id":8,
                        "name":"子节点2.2",
                        "nodeList":[]
                    }
                ]
            },
            {
   
   
                "id":9,
                "name":"子节点3", 
                "nodeList":[
                    {
   
   
                        "id":10,
                        "name":"子节点3.1",
                        "nodeList":[                        ]
                    }
                ]
            }
        ]
    }
]

上面的程序都是使用For循环来实现List集合转换到Tree结构,大家是否还记得JDK8的一个新特性 -- Lambda表达式, 可能使用Stream来简化处理,那么程序会是怎么样呢?

用Stream流式的代码:

public static List<TreeVo> toTree(List<Table> datas){
   
   
        //得到父节点
        List<TreeVo> roots = datas.stream()
                .filter(m -> m.getParentId() == null || m.getParentId() == 0)
                .map(m -> {
   
   
                    TreeVo vo = new TreeVo(m.getId(), m.getName());
                    vo.setNodeList(buildSubNodes(m, datas));
                    return vo;
                })
                .collect(Collectors.toList());
        return roots;
    }    private static List<TreeVo> buildSubNodes(Table root, List<Table> list){
   
   
        List<TreeVo> subNodes = list.stream()
                .filter(m -> Objects.equals(root.getId(), m.getParentId()))
                .map(m -> {
   
   
            TreeVo vo = new TreeVo(m.getId(), m.getName());
            vo.setNodeList(buildSubNodes(m, list));
            return vo;
        }).collect(Collectors.toList());
        return subNodes;
    }

测试用例:

    @Test
    public void Bo2TreeTest2(){
   
   
        List<TreeVo> result = TreeKit.toTree(tableData);
        log.info("Stream流:转换结果:{}", JsonUtil.toJson(result));
    }

输出结果:

[    {
   
           "id":1,        "name":"根节点",        "nodeList":[            {
   
                   "id":2,                "name":"子节点1",                "nodeList":[                    {
   
                           "id":3,                        "name":"子节点1.1",                        "nodeList":[                        ]
                    },
                    {
   
    
                       "id":4,
                        "name":"子节点1.2",
                        "nodeList":[
                        ]
                    },
                    {
   
   
                        "id":5,
                        "name":"子节点1.3",
                        "nodeList":[
                        ]
                    }
                ]
            },
            {
   
   
                "id":6,
                "name":"子节点2",
                "nodeList":[
                    {
   
   
                        "id":7,
                        "name":"子节点2.1",
                        "nodeList":[                        ]
                    },
                    {
   
   
                        "id":8,
                        "name":"子节点2.2",
                        "nodeList":[]
                    }
                ]
            },
            {
   
   
                "id":9,
                "name":"子节点3", 
                "nodeList":[
                    {
   
   
                        "id":10,
                        "name":"子节点3.1",
                        "nodeList":[                        ]
                    }
                ]
            }
        ]
    }
]

从输出的结果来看,流式的处理方式,一样也可以实现将List集合转化成Tree的结果。如果读者还有更好的方式,欢迎留言讨论。

如果需要测试用例的代码,可以访问:gitee.com/TianXiaoSe_…

目录
相关文章
|
10天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的服装商城管理系统
基于Java+Springboot+Vue开发的服装商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的服装商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
32 2
基于Java+Springboot+Vue开发的服装商城管理系统
|
8天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
基于Java+Springboot+Vue开发的大学竞赛报名管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的大学竞赛报名管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
23 3
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
|
9天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的蛋糕商城管理系统
基于Java+Springboot+Vue开发的蛋糕商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的蛋糕商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
21 3
基于Java+Springboot+Vue开发的蛋糕商城管理系统
|
9天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的美容预约管理系统
基于Java+Springboot+Vue开发的美容预约管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的美容预约管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
21 3
基于Java+Springboot+Vue开发的美容预约管理系统
|
10天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的房产销售管理系统
基于Java+Springboot+Vue开发的房产销售管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的房产销售管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
25 3
基于Java+Springboot+Vue开发的房产销售管理系统
|
11天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的反诈视频宣传系统
基于Java+Springboot+Vue开发的反诈视频宣传系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的反诈视频宣传管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
41 4
基于Java+Springboot+Vue开发的反诈视频宣传系统
|
12天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的健身房管理系统
基于Java+Springboot+Vue开发的健身房管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的健身房管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
42 5
基于Java+Springboot+Vue开发的健身房管理系统
|
9天前
|
存储 网络协议 Java
Java NIO 开发
本文介绍了Java NIO(New IO)及其主要组件,包括Channel、Buffer和Selector,并对比了NIO与传统IO的优势。文章详细讲解了FileChannel、SocketChannel、ServerSocketChannel、DatagramChannel及Pipe.SinkChannel和Pipe.SourceChannel等Channel实现类,并提供了示例代码。通过这些示例,读者可以了解如何使用不同类型的通道进行数据读写操作。
Java NIO 开发
|
11天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的医院门诊预约挂号系统
基于Java+Springboot+Vue开发的医院门诊预约挂号系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的门诊预约挂号管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
31 2
基于Java+Springboot+Vue开发的医院门诊预约挂号系统
|
12天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的家具管理系统
基于Java+Springboot+Vue开发的家具管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的家具管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
32 2
基于Java+Springboot+Vue开发的家具管理系统
下一篇
无影云桌面