addChild, Comparator super T> defaultComparator) {
this.identityGetter = identityGetter;
this.parentIdentityGetter = parentIdentityGetter;
this.addChildMethod = addChild;
+ this.defaultComparator = defaultComparator;
}
+ /**
+ * 将节点构建成树。使用 {@link #defaultComparator} 进行排序。如果 {@link #defaultComparator}
+ *
+ * 注意,该方法会直接操作 nodes 列表中的节点,并没有做深拷贝,
+ * 注意避免 nodes 中的元素产生变化所带来的意料之外的影响。
+ *
+ * @param nodes 平铺的节点列表
+ */
public List buildTree(Collection nodes) {
- Map identityNodeMap = nodes.stream()
+ Preconditions.checkNotNull(nodes);
+ return buildTreeInternal(nodes, this.defaultComparator);
+ }
+
+ /**
+ * 将节点构建成树。
+ *
+ * 注意,该方法会直接操作 nodes 列表中的节点,并没有做深拷贝,
+ * 注意避免 nodes 中的元素产生变化所带来的意料之外的影响。
+ *
+ * @param nodes 平铺的节点列表
+ * @param comparator 用于节点的排序。
+ * 若为 {@code null},则使用 {@link #defaultComparator};
+ * 若 {@link #defaultComparator} 也为 {@code null},则不排序。
+ */
+ public List buildTree(Collection nodes, @Nullable Comparator super T> comparator) {
+ Preconditions.checkNotNull(nodes);
+ final Comparator super T> c = (comparator != null) ? comparator : this.defaultComparator;
+ return buildTreeInternal(nodes, c);
+ }
+
+ /**
+ * 将节点构建成树。
+ *
+ * 注意,该方法会直接操作 nodes 列表中的节点,并没有做深拷贝,
+ * 注意避免 nodes 中的元素产生变化所带来的意料之外的影响。
+ *
+ * @param nodes 平铺的节点列表
+ * @param comparator 用于节点的排序。若为 {@code null},则不排序
+ */
+ private List buildTreeInternal(Collection nodes, @Nullable Comparator super T> comparator) {
+ final Collection allNodes;
+ if (comparator == null) {
+ allNodes = nodes;
+ } else {
+ allNodes = nodes.stream().sorted(comparator).collect(Collectors.toList());
+ }
+
+ final Map identityNodeMap = allNodes.stream()
.collect(Collectors.toMap(identityGetter, Function.identity(), (n1, n2) -> n1));
- List result = nodes.stream()
+ final List result = allNodes.stream()
.filter(node -> !this.parentIdentityGetter.apply(node).isPresent())
.collect(Collectors.toList());
- nodes.forEach(node -> parentIdentityGetter.apply(node).ifPresent(parentIdentity -> {
+ allNodes.forEach(node -> parentIdentityGetter.apply(node).ifPresent(parentIdentity -> {
if (identityNodeMap.containsKey(parentIdentity)) {
@SuppressWarnings("unchecked")
TSubTree parentNode = (TSubTree) identityNodeMap.get(parentIdentity);
diff --git a/src/test/java/xyz/zhouxy/plusone/commons/util/TreeBuilderTests.java b/src/test/java/xyz/zhouxy/plusone/commons/util/TreeBuilderTests.java
index 14b3828..7b7b842 100644
--- a/src/test/java/xyz/zhouxy/plusone/commons/util/TreeBuilderTests.java
+++ b/src/test/java/xyz/zhouxy/plusone/commons/util/TreeBuilderTests.java
@@ -17,29 +17,34 @@ class TreeBuilderTests {
private static final Logger log = LoggerFactory.getLogger(TreeBuilderTests.class);
private final TreeBuilder