本文目录导读:

针对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、前端等多种输出
- 合理的性能优化 - 根据数据量选择合适的方案
根据实际业务场景(数据量大小、展示要求、性能需求)选择最适合的方案即可。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播