使用Java8新特性构建树形结构:灵活的父子节点关系处理
· 阅读需 5 分钟
在实际开发中,树形结构广泛应用于组织和表示层级化数据,如文件目录、菜单导航、组织架构等。Java 8 的流式 API 和函数式编程特性为处理这类问题提供了极大的便利。下面将分享如何使用 Java 8 中的 Function
和 BiConsumer
等新特性,构建树形结构并处理父子节点关系。
项目背景
在许多业务场景中,我们经常需要根据节点的父子关系来构建一个树形结构。例如,一个简单的交易信息模型可能包含多个交易节点,节点之间有父子关系。通过这种方式,我们可以快速实现层级结构,并对数据进行灵活操作。
项目需求
我们需要实现一个方法,将一组数据根据父子关系构建成树形结构。在树形结构中,父节点将包含所有子节点。我们使用 Java 8 提供的流式操作来实现这一功能,同时利用函数式接口,如 Function
和 BiConsumer
,来提高代码的灵活性和可复用性。
关键技术
- BiConsumer:接受两个参数并返回
void
,我们用它来处理节点之间的父子关系,例如为父节点设置子节点。 - Function:接受一个 输入参数并返回一个结果,用于从节点中获取 ID 和父 ID。
- Stream API:通过流式操作对数据进行过滤和处理,避免了传统的嵌套循环方式。
代码实现
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 功能描述:
* 该类用于构建树形结构,基于给定的数据列表,将父子节点关系组织成层级化的树形结构。
* 通过使用 Java 8 新特性,如 Function 和 BiConsumer,灵活地处理节点间的父子关系。
* -
* 创建人: 季冠臣
* 创建时间: 2024/12/2 15:38
*/
public class TreeStructureTest {
// 模拟的节点类
static class TradeInfo {
private String tradeID; // 当前节点ID
private String parentID; // 父节点ID
private List<TradeInfo> children; // 子节点列表
public TradeInfo(String tradeID, String parentID) {
this.tradeID = tradeID;
this.parentID = parentID;
this.children = new ArrayList<>();
}
// Getter 和 Setter 方法
public String getTradeID() {
return tradeID;
}
public void setTradeID(String tradeID) {
this.tradeID = tradeID;
}
public String getParentID() {
return parentID;
}
public void setParentID(String parentID) {
this.parentID = parentID;
}
public List<TradeInfo> getChildren() {
return children;
}
public void setChildren(List<TradeInfo> children) {
this.children = children;
}
@Override
public String toString() {
return "TradeInfo{" +
"tradeID='" + tradeID + '\'' +
", parentID='" + parentID + '\'' +
", children=" + children +
'}';
}
}
// 构建树形结构
private static <T, R> List<T> buildTree(List<T> dataList, BiConsumer<T, List<T>> setChildF, Function<T, R> getIdF,
Function<T, R> getParentIdF, R rootParentId) {
if (dataList != null && !dataList.isEmpty()) {
setChildCall(dataList, setChildF, getIdF, getParentIdF, rootParentId);
dataList = dataList.stream()
.filter(t -> (rootParentId != null && rootParentId.equals(getParentIdF.apply(t)))
|| (rootParentId == null && getParentIdF.apply(t) == null))
.collect(Collectors.toList());
}
return dataList;
}
// 将子集放入父级
private static <T, R> List<T> setChildCall(List<T> dataList, BiConsumer<T, List<T>> setChildF, Function<T, R> getIdF,
Function<T, R> getParentIdF, R parentId) {
if (dataList == null || dataList.isEmpty()) {
return dataList;
}
List<T> parentChild = dataList.stream()
.filter(t -> parentId == null || (getParentIdF.apply(t) != null && getParentIdF.apply(t).equals(parentId)))
.collect(Collectors.toList());
for (T t : parentChild) {
setChildF.accept(t, setChildCall(dataList, setChildF, getIdF, getParentIdF, getIdF.apply(t)));
}
return parentChild;
}
public static void main(String[] args) {
// 创建示例数据
List<TradeInfo> dataList = Arrays.asList(
new TradeInfo("1", null),
new TradeInfo("2", "1"),
new TradeInfo("3", "1"),
new TradeInfo("4", "2"),
new TradeInfo("5", "2")
);
// 定义如何获取ID和父ID
Function<TradeInfo, String> getIdF = TradeInfo::getTradeID;
Function<TradeInfo, String> getParentIdF = TradeInfo::getParentID;
// 定义如何设置子节点
BiConsumer<TradeInfo, List<TradeInfo>> setChildF = TradeInfo::setChildren;
// 构建树结构
List<TradeInfo> tree = buildTree(dataList, setChildF, getIdF, getParentIdF, null);
// 输出结果
System.out.println("构建后的树形结构:");
tree.forEach(System.out::println);
}
}
代码解析
- TradeInfo 类:定义了一个简单的节点类,包含
tradeID
和parentID
,并通过children
列表存储子节点。 - buildTree 方法:这是树形结构构建的核心方法。它通过递归将子节点设置到父节点,并根据父节点 ID 筛选出该层级的节点。
- setChildCall 方法:该方法实现了递归的核心逻辑,通过
BiConsumer
将子节点设置到父节点,构建树形结构。 - 函数式接口:通过
Function
接口获取节点的 ID 和父 ID,通过BiConsumer
设置子节点,实现了灵活的节点关系操作。
输出结果
运行以上代码后,输出的树形结构将展示如下:
构建后的树形结构:
TradeInfo{tradeID='1', parentID='null', children=[TradeInfo{tradeID='2', parentID='1', children=[TradeInfo{tradeID='4', parentID='2', children=[]}, TradeInfo{tradeID='5', parentID='2', children=[]}]}, TradeInfo{tradeID='3', parentID='1', children=[]}]}
如上所示,我们成功地将交易信息列表组织成了树形结构。
小结
通过 Java 8 的函数式编程特性,我们可以更加简洁、灵活地处理复杂的父子节点关系。这种方法不仅适用于树形结构的构建,还能够广泛应用于其他需要层级关系的数据处理场景。例如,在处理文件目录、组织架构、菜单层级等问题时,采用类似的方法将大大提高代码的可读性和可维护性。
当然,在实际应用中,树形结构可能会更加复杂,涉及更多的业务逻辑。你可以根据自己的需求进行扩展和调整。希望本文能为你的开发工作提供一些启发!🚀
浏览量:加载中...