本文目录导读:

针对Java树形结构数据的规整,核心在于数据建模、递归处理和展示格式化,以下是几种常见场景的规整方案和代码示例:
核心数据模型设计
首先需要一个通用的树节点基类:
public class TreeNode<T> {
private T id; // 节点ID
private T parentId; // 父节点ID
private String name; // 节点名称
private List<TreeNode<T>> children; // 子节点列表
// 扩展字段(可选)
private Integer level; // 层级
private Boolean isLeaf; // 是否叶子节点
private String path; // 节点路径
public TreeNode() {
this.children = new ArrayList<>();
}
// 省略getter/setter和构造函数
}
从平面列表构建树
这是最常见的场景:数据库查询出的扁平数据转换为树形结构。
两次遍历法(推荐)
public class TreeBuilder {
public static <T> List<TreeNode<T>> buildTree(List<TreeNode<T>> flatList, T rootParentId) {
List<TreeNode<T>> treeList = new ArrayList<>();
// 1. 创建ID到节点的映射
Map<T, TreeNode<T>> nodeMap = new HashMap<>();
for (TreeNode<T> node : flatList) {
nodeMap.put(node.getId(), node);
}
// 2. 构建父子关系
for (TreeNode<T> node : flatList) {
T parentId = node.getParentId();
if (parentId == null || parentId.equals(rootParentId)) {
// 根节点
treeList.add(node);
} else {
// 非根节点,查找父节点
TreeNode<T> parent = nodeMap.get(parentId);
if (parent != null) {
parent.getChildren().add(node);
}
}
}
return treeList;
}
}
递归构建(适合小数据集)
public class RecursiveTreeBuilder {
public static <T> List<TreeNode<T>> buildTree(List<TreeNode<T>> flatList, T parentId) {
List<TreeNode<T>> treeNodes = new ArrayList<>();
for (TreeNode<T> node : flatList) {
if (parentId == null && node.getParentId() == null ||
parentId != null && parentId.equals(node.getParentId())) {
// 递归查找子节点
node.setChildren(buildTree(flatList, node.getId()));
treeNodes.add(node);
}
}
return treeNodes;
}
}
树形数据的显示规整
1 控制台输出(带缩进)
public class TreePrinter {
public static <T> void printTree(List<TreeNode<T>> treeList) {
for (TreeNode<T> node : treeList) {
printNode(node, 0);
}
}
private static <T> void printNode(TreeNode<T> node, int depth) {
// 缩进
StringBuilder indent = new StringBuilder();
for (int i = 0; i < depth; i++) {
indent.append(" ");
}
// 打印节点信息
System.out.println(indent + "├─ " + node.getName());
// 递归打印子节点
if (node.getChildren() != null) {
List<TreeNode<T>> children = node.getChildren();
for (int i = 0; i < children.size(); i++) {
TreeNode<T> child = children.get(i);
printNode(child, depth + 1);
}
}
}
}
2 JSON输出(用于前端展示)
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
public class TreeJsonFormatter {
public static <T> String toJson(List<TreeNode<T>> treeList) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
return mapper.writeValueAsString(treeList);
}
// 自定义格式化,添加层级和路径信息
public static <T> List<Map<String, Object>> formatForView(List<TreeNode<T>> treeList) {
List<Map<String, Object>> result = new ArrayList<>();
for (TreeNode<T> node : treeList) {
result.add(formatNode(node, 1, "0"));
}
return result;
}
private static <T> Map<String, Object> formatNode(TreeNode<T> node, int level, String path) {
Map<String, Object> nodeMap = new LinkedHashMap<>();
nodeMap.put("id", node.getId());
nodeMap.put("name", node.getName());
nodeMap.put("level", level);
nodeMap.put("path", path + "-" + node.getId());
nodeMap.put("isLeaf", node.getChildren() == null || node.getChildren().isEmpty());
// 递归处理子节点
if (node.getChildren() != null && !node.getChildren().isEmpty()) {
List<Map<String, Object>> childrenList = new ArrayList<>();
nodeMap.put("children", childrenList);
for (TreeNode<T> child : node.getChildren()) {
childrenList.add(formatNode(child, level + 1, path + "-" + node.getId()));
}
}
return nodeMap;
}
}
完整案例:部门树
实体类
public class Department {
private Long id;
private Long parentId;
private String name;
private String description;
// 转换为树节点
public TreeNode<Long> toTreeNode() {
TreeNode<Long> node = new TreeNode<>();
node.setId(this.id);
node.setParentId(this.parentId);
node.setName(this.name);
// 可以添加额外信息
node.setExtData(this);
return node;
}
}
使用示例
public class TreeDemo {
public static void main(String[] args) {
// 1. 模拟数据库查询结果
List<Department> departments = getDepartmentsFromDB();
// 2. 转换为树节点列表
List<TreeNode<Long>> nodeList = departments.stream()
.map(Department::toTreeNode)
.collect(Collectors.toList());
// 3. 构建树
List<TreeNode<Long>> tree = TreeBuilder.buildTree(nodeList, null);
// 4. 规整输出
System.out.println("=== 树形结构(控制台)===");
TreePrinter.printTree(tree);
System.out.println("\n=== JSON输出 ===");
try {
String json = TreeJsonFormatter.toJson(tree);
System.out.println(json);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("\n=== 前端友好格式 ===");
List<Map<String, Object>> viewData = TreeJsonFormatter.formatForView(tree);
viewData.forEach(System.out::println);
}
}
常用工具类库推荐
| 库 | 场景 | 特点 |
|---|---|---|
| Apache Commons Collections | 集合操作 | 提供 CollectionUtils 等工具 |
| Jackson | JSON 序列化 | JsonNode 可以天然表示树形 |
| Lombok | 简化模型 | @Data 自动生成 getter/setter |
| MyBatis-Plus | 数据库查询 | TreeSelect 注解支持递归查询 |
| Hutool | 通用工具 | TreeUtil 提供树构建和遍历 |
性能优化建议
-
数据库层面:
- 使用 WITH RECURSIVE(MySQL 8+)直接查询树结构
- 添加 level、path 字段存储层级信息
-
Java处理优化:
- 使用 HashMap 存储节点(O(1)查找)
- 避免递归过深(设置最大深度)
- 使用并行流处理大型数据集
-
展示优化:
- lazy load(延迟加载子节点)
- 只加载当前层级的数据
- 前端使用虚拟滚动
规整Java树形结构的关键在于:
- 通用数据模型 - 支持任意类型的主键
- 高效构建算法 - 推荐两次遍历法
- 灵活的展示格式 - 支持控制台、JSON、前端等多种输出
- 合理的性能优化 - 根据数据量选择合适的方案
根据实际业务场景(数据量大小、展示要求、性能需求)选择最适合的方案即可。