Comprehensive Guide to TreeUtil: Building, Traversing, Flattening, and Sorting Tree Structures in Java
This article presents a detailed walkthrough of the TreeUtil class, demonstrating how to construct hierarchical tree structures from flat lists, define tree nodes in Java, perform generic and functional implementations of makeTree, traverse trees using pre‑order, level‑order and post‑order methods, flatten trees back to lists, and sort tree nodes recursively, all illustrated with complete code examples.
The article begins with an introduction explaining why tree data structures are essential for representing hierarchical relationships such as department directories, menus, and file systems. It highlights the need for a reusable utility to convert flat relational data into a tree.
Tree Structure Introduction
A simple binary tree example is shown, followed by common application scenarios (department contacts, system menus, address selectors, folder directories, product categories, comment threads).
Java Tree Node Definition
@Data
public class MenuVo {
private Long id;
private Long pId;
private String name;
private Integer rank = 0;
private List
subMenus = new ArrayList<>();
}The article then introduces the generic makeTree method, which takes a list, a root predicate, a parent‑matching function, and a setter for child nodes to build the tree in a functional style.
public static
List
makeTree(List
list,
Predicate
rootCheck,
BiFunction
parentCheck,
BiConsumer
> setSubChildren) {
return list.stream()
.filter(rootCheck)
.peek(x -> setSubChildren.accept(x, makeChildren(x, list, parentCheck, setSubChildren)))
.collect(Collectors.toList());
}For readability, a non‑generic version is also provided, showing explicit recursion to find root nodes, attach children, and return the assembled roots.
Tree Traversal Utilities
Three traversal methods are described:
forPreOrder – processes the current node before its children.
forLevelOrder – breadth‑first traversal using a queue.
forPostOrder – processes children before the current node.
Each method receives the tree, a Consumer to handle each element, and a Function to retrieve child lists.
Flattening a Tree
The flat method uses forPostOrder to clear child references and collect all nodes back into a flat list.
public static
List
flat(List
tree,
Function
> getSubChildren,
Consumer
setSubChildren) {
List
res = new ArrayList<>();
forPostOrder(tree, item -> {
setSubChildren.accept(item);
res.add(item);
}, getSubChildren);
return res;
}Sorting Tree Nodes
The sort method recursively sorts each node’s children using a supplied Comparator and then sorts the current level.
public static
List
sort(List
tree,
Comparator
comparator,
Function
> getChildren) {
for (E item : tree) {
List
childList = getChildren.apply(item);
if (childList != null && !childList.isEmpty()) {
sort(childList, comparator, getChildren);
}
}
tree.sort(comparator);
return tree;
}Examples demonstrate sorting by a rank field in both ascending and descending order.
Conclusion
The author praises the elegance and reusability of TreeUtil, noting that complex recursive tree handling can now be achieved with concise static calls, making future tree‑related development much simpler.
Code Ape Tech Column
Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.