在系统开发过程中,可能会碰到一些需求,需要构建树形结构,数据库一般就使用父id来表示,比如构建菜单、构建地区级联、构建部门层级结构等等。虽然可以通过数据库SQL查询,但我们一般都是通过SQL一次性查询出所有数据,在程序中处理成树形结构。本文讲述如何将一个List
1、自己测试过没问题的:
/**
* 对象List转为Tree树形结构
*
* @param entityList 传进来的泛型List
* @param primaryFieldName 主键名称
* @param parentFieldName 父级字段名称
* @return
*/
public final List
2、for 方法转树形
public class TreeTest {
public static void main(String[] args) {
List node = forMethod(treeList);
System.out.println(node);
}
/**
* 双重for循环方法转换成树形结构
* @param treeList
* @return
*/
public static List forMethod(List treeList) {
List rootTree = new ArrayList<>();
for (Tree tree : treeList) {
// 第一步 筛选出最顶级的父节点
if (0 == tree.getParentId()) {
rootTree.add(tree);
}
// 第二步 筛选出该父节点下的所有子节点列表
for (Tree node : treeList) {
if (node.getParentId().equals(tree.getId())) {
if (CollectionUtils.isEmpty(tree.getChildren())) {
tree.setChildren(new ArrayList<>());
}
tree.getChildren().add(node);
}
}
}
return rootTree;
}
}
3、递归方法转树形
public class TreeTest {
public static void main(String[] args) {
List node = recursionMethod(treeList);
System.out.println(node);
}
/**
* 递归方法转换成树形结构
* @param treeList
* @return
*/
public static List recursionMethod(List treeList) {
List trees = new ArrayList<>();
for (Tree tree : treeList) {
// 找出父节点
if (0 == tree.getParentId()) {
// 调用递归方法填充子节点列表
trees.add(findChildren(tree, treeList));
}
}
return trees;
}
/**
* 递归方法
* @param tree 父节点对象
* @param treeList 所有的List
* @return
*/
public static Tree findChildren(Tree tree, List treeList) {
for (Tree node : treeList) {
if (tree.getId().equals(node.getParentId())) {
if (tree.getChildren() == null) {
tree.setChildren(new ArrayList<>());
}
// 递归 调用自身
tree.getChildren().add(findChildren(node, treeList));
}
}
return tree;
}
}
4、stream方法转树形
public class TreeTest {
public static void main(String[] args) {
List node = recursionMethod(treeList);
System.out.println(node);
}
/**
* stream方法转换成树形结构
* @param treeList
* @return
*/
public static List streamMethod(List treeList) {
List list = treeList.stream()
// 筛选出父节点
.filter(t -> t.getParentId() == 0)
// 设置父节点的子节点列表
.map(item -> {item.setChildren(streamGetChildren(item, treeList)); return item;})
.collect(Collectors.toList());
return list;
}
/**
* stream 方式递归查找子节点列表
* @return
*/
public static List streamGetChildren(Tree tree, List treeList) {
List list = treeList.stream()
.filter(t -> t.getParentId().equals(tree.getId()))
.map(item -> {item.setChildren(streamGetChildren(item, treeList)); return item;})
.collect(Collectors.toList());
return list;
}
}
5、stream 转树形优化
// 第一种优化,我们合并上述两个方法的相同部分
public class TreeTest {
public static void main(String[] args) {
List node = streamMethod(0, treeList);
System.out.println(node);
}
/**
* stream 方法转换树形结构方法的优化
* @param parentId
* @param treeList
* @return
*/
public static List streamMethod(Integer parentId, List treeList) {
List list = treeList.stream()
// 筛选父节点
.filter(t -> t.getParentId().equals(parentId))
// 递归设置子节点
.map(item -> {
item.setChildren(streamMethod(item.getId(), treeList));
return item;
})
.collect(Collectors.toList());
return list;
}
}
// 第二种优化,只是写法的不同,核心思路不变
public class TreeTest {
public static void main(String[] args) {
List node = streamMethod(0, treeList);
System.out.println(node);
}
/**
* stream 方法转换树形结构方法的优化
* @param parentId
* @param treeList
* @return
*/
public static List streamMethod(Integer parentId, List treeList) {
List list = new ArrayList<>();
Optional.ofNullable(treeList).orElse(new ArrayList<>())
.stream()
// 第一次筛选出主父节点列表进入循环,循环里面 进入递归 筛选出递归传递的从父节点列表
.filter(root -> root.getParentId().equals(parentId))
// 递归,最末的父节点从整个列表筛选出它的子节点列表依次组装
.forEach(tree -> {
List children = streamMethod(tree.getId(), treeList);
tree.setChildren(children);
list.add(tree);
});
return list;
}
}
经过上面的代码,我们已经成功的将 List
数据库或者构造的集合数据中的文件数量只统计了文件夹本身下面的文件数量,并没有加上子文件夹里面的所有文件夹数量。我们需要将子文件夹的 count 属性逐
级累加到父节点的 count 属性中更新它。
public class TreeTest {
public static void main(String[] args) {
// treeList 是已经处理好的 树形结构 集合
countHandler(treeList);
System.out.println(treeList);
}
/**
* 递归将子节点属性值累加给父节点
* @param treeList
* @return
*/
private int countHandler(List treeList) {
int count = 0;
if(CollectionUtil.isEmpty(treeList)){
return count;
}
for (Tree tree : treeList) {
count += tree.getCount();
if (CollectionUtil.isEmpty(tree.getChildren())) {
continue;
}
count += countHandler(tree.getChildren());
tree.setCount(count);
if (tree.getParentId() == null || tree.getParentId() == 0) {
count = 0;
}
}
return count;
}
}