前言
在开发的过程中很多业务场景需要一个树形结构的结果集进行前端展示,比如菜单结构、部门列表、文件结构等,也可以理解为是一个无限父子结构。
树形结构类如下:
@Data
public class Category {
//唯一id
private Long id;
//名称
private String name;
//父id,为null表示定义父类
private Long parentId;
//所属子类
private List<Category> children;
//同一级分类排序
private Integer sort;
public Category(Long id, String name, Long parentId) {
this.id = id;
this.name = name;
this.parentId = parentId;
}
}
原始递归
public class Test1 {
public static void main(String[] args) {
// 获取顶级分类列表,并打印为JSON格式
List<Category> categories = parentList01();
System.out.println(JSON.toJSONString(categories, true));
}
// 获取顶级分类列表的方法
private static List<Category> parentList01() {
// 过滤出parentId为null的顶级分类
List<Category> parentList = Category.categories.stream()
.filter(category -> category.getParentId() == null)
.collect(Collectors.toList());
// 为每个顶级分类设置其子分类
for (Category category : parentList) {
category.setChildren(buildChildren(category.getId(), Category.categories));
}
return parentList;
}
// 递归构建子分类列表的方法
private static List<Category> buildChildren(Long id, List<Category> categories) {
List<Category> children = new ArrayList<>();
for (Category category : categories) {
// 跳过parentId不为null的非顶级分类(这里实际上是多余的,因为外层循环已经过滤了顶级分类)
if (category.getParentId() != null) {
continue;
}
// 找到parentId等于指定id的分类,加入到子分类列表中
if (category.getParentId().equals(id)) {
children.add(category);
}
}
// 递归地为每个子分类设置其子分类
for (Category child : children) {
child.setChildren(buildChildren(child.getId(), categories));
}
return children;
}
}
利用Java 8 Stream流进行处理(原理还是递归)
public class Test2 {
/**
* 获取带有树形结构的分类列表
*
* @return 分类的树形结构列表
*/
public static List<Category> listWithTree() {
//1、查询所有分类
List<Category> entities = Category.categories; // 假设Category.categories包含了所有分类的静态列表
//2、将这些分类组装成父子关系的树形结构
//2.1)找到所有的一级分类,并为它们设置子分类
return entities.stream()
// 过滤出所有的一级分类(即父分类ID为null的分类)
.filter(category -> category.getParentId() == null)
// 处理每个一级分类,递归地为它们设置子菜单
.peek(menu -> menu.setChildren(getChildless(menu, entities)))
// 根据sort属性对分类进行排序
.sorted(Comparator.comparingInt(c -> c.getSort() == null ? 0 : c.getSort()))
.collect(Collectors.toList()); // 收集结果到列表中
}
/**
* 递归查找给定根分类的所有子分类
*
* @param root 根分类
* @param all 所有分类的列表
* @return 根分类的所有子分类列表
*/
private static List<Category> getChildless(Category root, List<Category> all) {
return all.stream()
// 过滤出所有父分类ID等于当前根分类ID的分类
.filter(category -> root.getId().equals(category.getParentId()))
.peek(category -> {
// 递归地为每个子分类设置其子分类
category.setChildren(getChildless(category, all));
})
// 根据sort属性对子分类进行排序
.sorted(Comparator.comparingInt(c -> c.getSort() == null ? 0 : c.getSort()))
.collect(Collectors.toList()); // 收集结果到列表中
}
/**
* 主方法,用于测试listWithTree方法
*
* @param args 命令行参数
*/
public static void main(String[] args) {
// 将树形结构的分类列表转换为JSON字符串并打印出来
System.out.println(JSON.toJSONString(listWithTree(), true));
}
}
Stream流升级构建
public class Test3 {
// 主方法,程序的入口点
public static void main(String[] args) {
// 将树形结构的分类列表转换为JSON字符串并打印出来
// 假设JSON.toJSONString是一个将对象转换为JSON字符串的静态方法
System.out.println(JSON.toJSONString(listWithTree(), true));
}
// 构建树形结构的分类列表
public static List<Category> listWithTree() {
// 从某个静态源(可能是数据库或配置)获取所有分类的列表
List<Category> categories = Category.categories;
// 过滤出所有一级分类(即父分类ID为null的分类),并为每个一级分类设置子分类
List<Category> collect = categories
.stream() // 将列表转换为流
.filter(m -> m.getParentId() == null) // 过滤出一级分类
.map((m) -> { // 对每个一级分类进行处理
m.setChildren(getChildrenList(m, categories)); // 设置子分类
return m; // 返回处理后的分类
})
.collect(Collectors.toList()); // 收集结果到新的列表中
return collect; // 返回构建好的树形结构列表
}
/**
* 获取子节点列表
* @param tree 父节点
* @param list 分类列表
* @return 子节点列表
*/
public static ListCategory> getChildrenList(Category tree, List<Category> list) {
// 从列表中过滤出所有父分类ID等于给定父分类ID的分类
List<Category> children = list
.stream()
.filter(item -> Objects.equals(item.getParentId(), tree.getId()))
.map((item) -> { // 对每个子分类进行处理
item.setChildren(getChildrenList(item, list)); // 递归设置子分类的子分类
return item; // 返回处理后的子分类
})
.collect(Collectors.toList()); // 收集结果到新的列表中
return children; // 返回构建好的子分类列表
}
}
1万+

被折叠的 条评论
为什么被折叠?



