【实用工具】Java将对象列表转成树结构的两种方法

Java将对象列表转成树结构的两种方法

应用背景

在系统开发过程中,可能会碰到一些需求,需要构建树形结构,数据库一般就使用父id来表示,比如构建菜单、构建地区级联、构建部门层级结构等等。虽然可以通过数据库SQL查询,但我们一般都是通过SQL一次性查询出所有数据,在程序中处理成树形结构。
在这里插入图片描述

使用lambda表达式+递归

构建树的对象

@Data
public class Menu extends TreeEntity<Menu> {

    public Menu(Long id, Long parentId, String title, Integer level) {
        this.setId(id);
        this.setParentId(parentId);
        this.title = title;
        this.level = level;
    }

    private String title;

    private Integer level;
}

@Data
public class TreeEntity<T> {

    private static final long serialVersionUID = 1L;

    private Long id;
    /**
     * 父菜单ID
     */
    private Long parentId;

    /**
     * 子部门
     */
    private List<T> children = new ArrayList<>();

}

生成树的工具类

public class ForestNodeMerger {

    //将节点数组归并为一个森林(多棵树)(填充节点的children域)
    public static <T extends TreeEntity<T>> List<T> merge(List<T> items) {
        //获取parentId = -1l的根节点
        List<T> list = items.stream().filter(item -> item.getParentId() == -1L).collect(Collectors.toList());
        //根据parentId进行分组
        Map<Long, List<T>> map = items.stream().collect(Collectors.groupingBy(TreeEntity::getParentId));
        recursionFnTree(list, map);
        return list;
    }

    public static <T extends TreeEntity<T>> void recursionFnTree(List<T> list, Map<Long, List<T>> map) {
        for (T treeSelect : list) {
            List<T> childList = map.get(treeSelect.getId());
            if (null != childList && 0 < childList.size()) {
                treeSelect.setChildren(childList);
                recursionFnTree(childList, map);
            } else {
                treeSelect.setChildren(null);
            }
        }
    }
}

示例

    @Test
    public void t1() throws Exception {
        Menu menu1 = new Menu(1L, -1L, "aa", 1);
        Menu menu2 = new Menu(2L, -1L, "bb", 1);
        Menu menu3 = new Menu(3L, 1L, "cc", 2);
        Menu menu4 = new Menu(4L, 1L, "dd", 2);
        List<Menu> menuList = Arrays.asList(menu1, menu2, menu3, menu4);
        List<Menu> mergeList = ForestNodeMerger.merge(menuList);
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(mergeList);
        System.out.println(jsonStr);
    }
[
	{
		"id": 1,
		"parentId": -1,
		"children": [
			{
				"id": 3,
				"parentId": 1,
				"children": null,
				"title": "cc",
				"level": 2
			},
			{
				"id": 4,
				"parentId": 1,
				"children": null,
				"title": "dd",
				"level": 2
			}
		],
		"title": "aa",
		"level": 1
	},
	{
		"id": 2,
		"parentId": -1,
		"children": null,
		"title": "bb",
		"level": 1
	}
]

使用Hutool的TreeUtil

加入hutool的依赖

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.18</version>
        </dependency>

示例

    @Test
	public void t2() throws Exception {
        Menu menu1 = new Menu(1L, -1L, "aa", 1);
        Menu menu2 = new Menu(2L, -1L, "bb", 1);
        Menu menu3 = new Menu(3L, 1L, "cc", 2);
        Menu menu4 = new Menu(4L, 1L, "dd", 2);
        List<Menu> menuList = Arrays.asList(menu1, menu2, menu3, menu4);
        TreeNodeConfig config = new TreeNodeConfig();
        //id
        config.setIdKey("id");
        //父id
        config.setParentIdKey("parentId");
        //排序字段
//        config.setWeightKey("sort");
        List<Tree<Long>> treeList = TreeUtil.build(menuList, -1L, config, ((object, treeNode) -> {
            //对key进行映射赋值
            treeNode.putExtra("id", object.getId());
            treeNode.putExtra("parentId", object.getParentId());
            treeNode.putExtra("title", object.getTitle());
            treeNode.putExtra("level", object.getLevel());
        }));
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = objectMapper.writeValueAsString(treeList);
        System.out.println(jsonStr);
    }
//[{"id":1,"parentId":-1,"title":"aa","level":1,"children":[{"id":3,"parentId":1,"title":"cc","level":2},{"id":4,"parentId":1,"title":"dd","level":2}]},{"id":2,"parentId":-1,"title":"bb","level":1}]
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值