From aba35cc6c2704e73368f66b97dc1dc9141c86f11 Mon Sep 17 00:00:00 2001 From: emptypoint <1215582715@qq.com> Date: Sun, 18 Sep 2022 12:49:01 +0800 Subject: [PATCH 01/16] =?UTF-8?q?predicate.test=E7=9A=84=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E7=BB=93=E6=9E=9C=E4=B8=8D=E8=83=BD=E4=B8=BAnull;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/hutool/core/stream/EasyStream.java | 7 ++----- .../test/java/cn/hutool/core/stream/EasyStreamTest.java | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index 90de48122..6a497ea33 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -313,11 +313,8 @@ public class EasyStream extends AbstractEnhancedWrappedStream parentPredicate) { Objects.requireNonNull(parentPredicate); final List list = toList(); - final List parents = EasyStream.of(list).filter(e -> - // 此处是为了适配 parentPredicate.test空指针 情况 - // 因为Predicate.test的返回值是boolean,所以如果 e -> null 这种返回null的情况,会直接抛出NPE - Opt.ofTry(() -> parentPredicate.test(e)).filter(Boolean::booleanValue).isPresent()) - .toList(); + // 根节点列表 + final List parents = EasyStream.of(list).filter(parentPredicate).toList(); return getChildrenFromMapByPidAndSet(idGetter, childrenSetter, EasyStream.of(list).group(pIdGetter), parents); } diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java index 26fa81ef8..c8a810fb9 100644 --- a/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java @@ -476,7 +476,7 @@ public class EasyStreamTest { Student.builder().id(8L).name("jobob").parentId(5L).build() ) // just 4 lambda ,top by condition - .toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent); + .toTree(Student::getId, Student::getParentId, Student::setChildren, Student::isMatchParent); Assert.assertEquals(asList( Student.builder().id(1L).name("dromara").matchParent(true) .children(asList(Student.builder().id(3L).name("hutool").parentId(1L) @@ -540,7 +540,7 @@ public class EasyStreamTest { private Long id; private Long parentId; private List children; - private Boolean matchParent = false; + private boolean matchParent; @Tolerate public Student() { From 9417bbee2e5b5448953e2dc6956160d53bd66a5d Mon Sep 17 00:00:00 2001 From: emptypoint <1215582715@qq.com> Date: Sun, 18 Sep 2022 20:04:46 +0800 Subject: [PATCH 02/16] =?UTF-8?q?=E8=A7=84=E8=8C=83Test=E4=B8=ADPOJO?= =?UTF-8?q?=E7=9A=84=E4=BD=BF=E7=94=A8;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/java/cn/hutool/core/stream/EasyStreamTest.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java index c8a810fb9..9ea222491 100644 --- a/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java @@ -2,6 +2,7 @@ package cn.hutool.core.stream; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.BooleanUtil; import lombok.Data; import lombok.experimental.Tolerate; import org.junit.Assert; @@ -476,7 +477,7 @@ public class EasyStreamTest { Student.builder().id(8L).name("jobob").parentId(5L).build() ) // just 4 lambda ,top by condition - .toTree(Student::getId, Student::getParentId, Student::setChildren, Student::isMatchParent); + .toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent); Assert.assertEquals(asList( Student.builder().id(1L).name("dromara").matchParent(true) .children(asList(Student.builder().id(3L).name("hutool").parentId(1L) @@ -540,12 +541,16 @@ public class EasyStreamTest { private Long id; private Long parentId; private List children; - private boolean matchParent; + private Boolean matchParent; @Tolerate public Student() { // this is an accessible parameterless constructor. } + + public Boolean getMatchParent() { + return BooleanUtil.isTrue(matchParent); + } } @Test From 28f6a76933d03fb810294f5a68deb2991612c087 Mon Sep 17 00:00:00 2001 From: emptypoint <1215582715@qq.com> Date: Sun, 18 Sep 2022 20:54:33 +0800 Subject: [PATCH 03/16] =?UTF-8?q?=E4=BC=98=E5=8C=96toTree=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E7=9A=84=E5=AE=9E=E7=8E=B0=EF=BC=8C=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E5=BE=AA=E7=8E=AF=E4=BB=A3=E6=9B=BF=E9=80=92=E5=BD=92;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/core/stream/EasyStream.java | 62 +++++++------------ 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index 6a497ea33..5bcf148c2 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -1,7 +1,7 @@ package cn.hutool.core.stream; +import cn.hutool.core.collection.ListUtil; import cn.hutool.core.lang.Opt; -import cn.hutool.core.lang.mutable.MutableObj; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjUtil; @@ -267,7 +267,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream将集合转换为树,默认用 {@code parentId == null} 作为顶部,内置一个小递归 + *

将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点 * 因为需要在当前传入数据里查找,所以这是一个结束操作
* * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} @@ -285,12 +285,13 @@ public class EasyStream extends AbstractEnhancedWrappedStream idGetter, final Function pIdGetter, final BiConsumer> childrenSetter) { - final Map> pIdValuesMap = group(pIdGetter); - return getChildrenFromMapByPidAndSet(idGetter, childrenSetter, pIdValuesMap, pIdValuesMap.get(null)); + // 使用 parentId == null 判断是否为根节点 + final Predicate parentPredicate = node -> null == pIdGetter.apply(node); + return toTree(idGetter, pIdGetter, childrenSetter, parentPredicate); } /** - * 将集合转换为树,自定义树顶部的判断条件,内置一个小递归(没错,lambda可以写递归) + * 将集合转换为树,自定义根节点的判断条件 * 因为需要在当前传入数据里查找,所以这是一个结束操作 * * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} @@ -305,46 +306,31 @@ public class EasyStream extends AbstractEnhancedWrappedStream */ - public > List toTree( final Function idGetter, final Function pIdGetter, final BiConsumer> childrenSetter, final Predicate parentPredicate) { - Objects.requireNonNull(parentPredicate); - final List list = toList(); - // 根节点列表 - final List parents = EasyStream.of(list).filter(parentPredicate).toList(); - return getChildrenFromMapByPidAndSet(idGetter, childrenSetter, EasyStream.of(list).group(pIdGetter), parents); - } - - /** - * toTree的内联函数,内置一个小递归(没错,lambda可以写递归) - * 因为需要在当前传入数据里查找,所以这是一个结束操作 - * - * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} - * @param childrenSetter children的setter对应的lambda,可以写作 {@code Student::setChildren} - * @param pIdValuesMap parentId和值组成的map,用来降低复杂度 - * @param parents 顶部数据 - * @param 此处是id的泛型限制 - * @return list 组装好的树 - */ - private > List getChildrenFromMapByPidAndSet( - final Function idGetter, - final BiConsumer> childrenSetter, - final Map> pIdValuesMap, - final List parents) { Objects.requireNonNull(idGetter); + Objects.requireNonNull(pIdGetter); Objects.requireNonNull(childrenSetter); - Objects.requireNonNull(pIdValuesMap); - final MutableObj>> recursiveRef = new MutableObj<>(); - final Consumer> recursive = values -> EasyStream.of(values, isParallel()).forEach(value -> { - final List children = pIdValuesMap.get(idGetter.apply(value)); - childrenSetter.accept(value, children); - recursiveRef.get().accept(children); - }); - recursiveRef.set(recursive); - recursive.accept(parents); + Objects.requireNonNull(parentPredicate); + + List nodeList = toList(); + // 父id 关联的 子节点列表 + final Map> pId2ChildrenMap = of(nodeList).group(pIdGetter); + List parents = ListUtil.of(); + + for (T node : nodeList) { + if (parentPredicate.test(node)) { + parents.add(node); + } + // 设置 该节点的子节点列表 + final List children = pId2ChildrenMap.get(idGetter.apply(node)); + if (children != null) { + childrenSetter.accept(node, children); + } + } return parents; } From 03a25799840bb039cfd6646d0571fd821173a820 Mon Sep 17 00:00:00 2001 From: emptypoint <1215582715@qq.com> Date: Sun, 18 Sep 2022 21:07:15 +0800 Subject: [PATCH 04/16] =?UTF-8?q?=E4=BD=BF=E7=94=A8=E5=B9=B6=E8=A1=8C?= =?UTF-8?q?=E6=B5=81=EF=BC=8C=E6=8F=90=E9=AB=98=E5=A4=A7=E9=87=8F=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E5=9C=BA=E6=99=AF=E4=B8=8B=E7=9A=84=E6=80=A7=E8=83=BD?= =?UTF-8?q?;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/hutool/core/stream/EasyStream.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index 5bcf148c2..b100d14f1 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -321,7 +321,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream> pId2ChildrenMap = of(nodeList).group(pIdGetter); List parents = ListUtil.of(); - for (T node : nodeList) { + of(nodeList, true).forEach(node -> { if (parentPredicate.test(node)) { parents.add(node); } @@ -330,7 +330,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream Date: Sun, 18 Sep 2022 22:46:25 +0800 Subject: [PATCH 05/16] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=A0=B9=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E4=B8=BAnull=E6=97=B6=E7=9A=84=E5=9C=BA=E6=99=AF;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/core/stream/EasyStream.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index b100d14f1..bbda79b8c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -1,10 +1,10 @@ package cn.hutool.core.stream; -import cn.hutool.core.collection.ListUtil; import cn.hutool.core.lang.Opt; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjUtil; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; @@ -317,21 +317,27 @@ public class EasyStream extends AbstractEnhancedWrappedStream nodeList = toList(); + // 根据 父id 分组,让key为null的组中全是根节点 + final Function pIdClassifier = node -> { + R parentId = pIdGetter.apply(node); + // 父id为null(另类的根节点),或者是根节点 + if (parentId == null || parentPredicate.test(node)) { + return null; + } + return parentId; + }; // 父id 关联的 子节点列表 - final Map> pId2ChildrenMap = of(nodeList).group(pIdGetter); - List parents = ListUtil.of(); + final Map> pId2ChildrenMap = of(nodeList).group(pIdClassifier); of(nodeList, true).forEach(node -> { - if (parentPredicate.test(node)) { - parents.add(node); - } // 设置 该节点的子节点列表 final List children = pId2ChildrenMap.get(idGetter.apply(node)); if (children != null) { childrenSetter.accept(node, children); } }); - return parents; + // 返回根节点列表 + return pId2ChildrenMap.getOrDefault(null, Collections.emptyList()); } /** From df748856d7475dfabf684658cbdd1064366036c2 Mon Sep 17 00:00:00 2001 From: Zjp <1215582715@qq.com> Date: Mon, 19 Sep 2022 09:01:12 +0800 Subject: [PATCH 06/16] =?UTF-8?q?=E5=87=8F=E5=B0=91=E9=A2=9D=E5=A4=96?= =?UTF-8?q?=E7=9A=84=E5=88=A4=E6=96=AD;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/hutool/core/stream/EasyStream.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index bbda79b8c..f2af24e8b 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -319,12 +319,12 @@ public class EasyStream extends AbstractEnhancedWrappedStream nodeList = toList(); // 根据 父id 分组,让key为null的组中全是根节点 final Function pIdClassifier = node -> { - R parentId = pIdGetter.apply(node); - // 父id为null(另类的根节点),或者是根节点 - if (parentId == null || parentPredicate.test(node)) { + // 该节点是根节点, 分到 父id 为null的组中 + if (parentPredicate.test(node)) { return null; } - return parentId; + // 返回 父id + return pIdGetter.apply(node); }; // 父id 关联的 子节点列表 final Map> pId2ChildrenMap = of(nodeList).group(pIdClassifier); From 41ce120da56a05706c548b3f201209ddc9c46b7f Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Mon, 19 Sep 2022 11:16:27 +0800 Subject: [PATCH 07/16] =?UTF-8?q?:trollface:=20=E4=BC=98=E5=8C=96toTree?= =?UTF-8?q?=E6=80=A7=E8=83=BD=EF=BC=8C=E6=8A=BD=E5=8F=96=E5=88=B0Collector?= =?UTF-8?q?Util=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/core/stream/CollectorUtil.java | 133 +++++++++++++++++- .../cn/hutool/core/stream/EasyStream.java | 54 ++----- .../cn/hutool/core/stream/EasyStreamTest.java | 8 +- 3 files changed, 144 insertions(+), 51 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index 14ffe6b6c..9b9e483dc 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -1,14 +1,12 @@ package cn.hutool.core.stream; import cn.hutool.core.lang.Opt; +import cn.hutool.core.lang.mutable.MutableObj; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ArrayUtil; import java.util.*; -import java.util.function.BiConsumer; -import java.util.function.BinaryOperator; -import java.util.function.Function; -import java.util.function.Supplier; +import java.util.function.*; import java.util.stream.Collector; import java.util.stream.Collectors; @@ -371,4 +369,131 @@ public class CollectorUtil { public static Collector, ?, Map> entryToMap() { return toMap(Map.Entry::getKey, Map.Entry::getValue); } + + /** + *

将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点,内置一个递归,注意内存开销 + * 因为需要在当前传入数据里查找,所以这是一个结束操作
+ * + * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} + * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} + * @param childrenSetter children的setter对应的lambda,可以写作{ @code Student::setChildren} + * @param isParallel 是否并行去组装,数据量特别大时使用 + * @param 此处是元素类型 + * @param 此处是id、parentId的泛型限制 + * @return list 组装好的树
+ * eg: + *

{@code
+	 * List studentTree = students.stream().collect(toTree(Student::getId, Student::getParentId, Student::setChildren, isParallel));
+	 * }
+ */ + public static , T> Collector> toTree( + final Function idGetter, + final Function pIdGetter, + final BiConsumer> childrenSetter, + final boolean isParallel) { + return toTree(idGetter, pIdGetter, null, childrenSetter, isParallel); + } + + /** + *

将集合转换为树,默认用 {@code parentId == pidValue} 来判断树的根节点,可以为null,内置一个递归,注意内存开销 + * 因为需要在当前传入数据里查找,所以这是一个结束操作
+ * + * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} + * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} + * @param childrenSetter children的setter对应的lambda,可以写作{ @code Student::setChildren} + * @param isParallel 是否并行去组装,数据量特别大时使用 + * @param 此处是元素类型 + * @param 此处是id、parentId的泛型限制 + * @return list 组装好的树
+ * eg: + *

{@code
+	 * List studentTree = students.stream().collect(toTree(Student::getId, Student::getParentId, 0L, Student::setChildren, isParallel));
+	 * }
+ * @author VampireAchao + */ + public static , T> Collector> toTree( + final Function idGetter, + final Function pIdGetter, + final R pidValue, + final BiConsumer> childrenSetter, + final boolean isParallel) { + return Collectors.collectingAndThen(groupingBy(pIdGetter, Collectors.toList()), + getChildrenFromMapByPidAndSet(idGetter, pIdValuesMap -> pIdValuesMap.get(pidValue), childrenSetter, isParallel)); + } + + /** + * 将集合转换为树,自定义根节点的判断条件,内置一个递归,注意内存开销 + * 因为需要在当前传入数据里查找,所以这是一个结束操作 + * + * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} + * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} + * @param childrenSetter children的setter对应的lambda,可以写作 {@code Student::setChildren} + * @param parentPredicate 树顶部的判断条件,可以写作 {@code s -> Objects.equals(s.getParentId(),0L) } + * @param 此处是元素类型 + * @param 此处是id、parentId的泛型限制 + * @return list 组装好的树
+ * eg: + *
{@code
+	 * List studentTree = EasyStream.of(students).
+	 * 	.toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent);
+	 * }
+ * @author VampireAchao + */ + public static , T> Collector> toTree( + final Function idGetter, + final Function pIdGetter, + final BiConsumer> childrenSetter, + final Predicate parentPredicate, + boolean isParallel) { + List parents = new ArrayList<>(); + return Collectors.collectingAndThen(groupingBy(pIdGetter, + new SimpleCollector<>(ArrayList::new, + (acc, e) -> { + if (parentPredicate.test(e)) { + parents.add(e); + } + acc.add(e); + }, + (left, right) -> { + left.addAll(right); + return left; + }, + CH_ID)), + getChildrenFromMapByPidAndSet(idGetter, pIdValuesMap -> parents, childrenSetter, isParallel)); + } + + /** + * toTree的内联函数,内置一个小递归(没错,lambda可以写递归) + * 因为需要在当前传入数据里查找,所以这是一个结束操作 + * + * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} + * @param parentFactory 顶部数据工厂方法 + * @param childrenSetter children的setter对应的lambda,可以写作 {@code Student::setChildren} + * @param isParallel 是否并行处理 + * @param 此处是元素类型 + * @param 此处是id的泛型限制 + * @return list 组装好的树 + * @author VampireAchao + */ + private static , T> Function>, List> getChildrenFromMapByPidAndSet( + final Function idGetter, + final Function>, List> parentFactory, + final BiConsumer> childrenSetter, + boolean isParallel) { + return pIdValuesMap -> { + final MutableObj>> recursiveRef = new MutableObj<>(); + final Consumer> recursive = parents -> EasyStream.of(parents, isParallel).forEach(parent -> { + final List children = pIdValuesMap.get(idGetter.apply(parent)); + childrenSetter.accept(parent, children); + recursiveRef.get().accept(children); + }); + List parents = parentFactory.apply(pIdValuesMap); + if (!parents.isEmpty()) { + recursiveRef.set(recursive); + recursiveRef.get().accept(parents); + } + return parents; + }; + } + } diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index f2af24e8b..9b77b1cf5 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -4,9 +4,7 @@ import cn.hutool.core.lang.Opt; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjUtil; -import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Spliterator; import java.util.function.*; @@ -267,7 +265,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点 + *

将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点,内置一个递归,注意内存开销 * 因为需要在当前传入数据里查找,所以这是一个结束操作
* * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} @@ -280,18 +278,17 @@ public class EasyStream extends AbstractEnhancedWrappedStream studentTree = EasyStream.of(students). * toTree(Student::getId, Student::getParentId, Student::setChildren); * } + * @author VampireAchao */ public > List toTree( - final Function idGetter, - final Function pIdGetter, - final BiConsumer> childrenSetter) { - // 使用 parentId == null 判断是否为根节点 - final Predicate parentPredicate = node -> null == pIdGetter.apply(node); - return toTree(idGetter, pIdGetter, childrenSetter, parentPredicate); + final Function idGetter, + final Function pIdGetter, + final BiConsumer> childrenSetter) { + return collect(CollectorUtil.toTree(idGetter, pIdGetter, childrenSetter, isParallel())); } /** - * 将集合转换为树,自定义根节点的判断条件 + * 将集合转换为树,自定义根节点的判断条件,内置一个递归,注意内存开销 * 因为需要在当前传入数据里查找,所以这是一个结束操作 * * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} @@ -305,39 +302,14 @@ public class EasyStream extends AbstractEnhancedWrappedStream studentTree = EasyStream.of(students). * .toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent); * } + * @author VampireAchao */ public > List toTree( - final Function idGetter, - final Function pIdGetter, - final BiConsumer> childrenSetter, - final Predicate parentPredicate) { - Objects.requireNonNull(idGetter); - Objects.requireNonNull(pIdGetter); - Objects.requireNonNull(childrenSetter); - Objects.requireNonNull(parentPredicate); - - List nodeList = toList(); - // 根据 父id 分组,让key为null的组中全是根节点 - final Function pIdClassifier = node -> { - // 该节点是根节点, 分到 父id 为null的组中 - if (parentPredicate.test(node)) { - return null; - } - // 返回 父id - return pIdGetter.apply(node); - }; - // 父id 关联的 子节点列表 - final Map> pId2ChildrenMap = of(nodeList).group(pIdClassifier); - - of(nodeList, true).forEach(node -> { - // 设置 该节点的子节点列表 - final List children = pId2ChildrenMap.get(idGetter.apply(node)); - if (children != null) { - childrenSetter.accept(node, children); - } - }); - // 返回根节点列表 - return pId2ChildrenMap.getOrDefault(null, Collections.emptyList()); + final Function idGetter, + final Function pIdGetter, + final BiConsumer> childrenSetter, + final Predicate parentPredicate) { + return collect(CollectorUtil.toTree(idGetter, pIdGetter, childrenSetter, parentPredicate, isParallel())); } /** diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java index 9ea222491..166a3f201 100644 --- a/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/stream/EasyStreamTest.java @@ -182,7 +182,7 @@ public class EasyStreamTest { Assert.assertEquals(collect2, distinctBy2); Assert.assertEquals( - 4, EasyStream.of(1, 2, 2, null, 3, null).parallel(true).distinct(t -> Objects.isNull(t) ? null : t.toString()).sequential().count() + 4, EasyStream.of(1, 2, 2, null, 3, null).parallel(true).distinct(t -> Objects.isNull(t) ? null : t.toString()).sequential().count() ); } @@ -477,7 +477,7 @@ public class EasyStreamTest { Student.builder().id(8L).name("jobob").parentId(5L).build() ) // just 4 lambda ,top by condition - .toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent); + .toTree(Student::getId, Student::getParentId, Student::setChildren, s -> BooleanUtil.isTrue(s.getMatchParent())); Assert.assertEquals(asList( Student.builder().id(1L).name("dromara").matchParent(true) .children(asList(Student.builder().id(3L).name("hutool").parentId(1L) @@ -547,10 +547,6 @@ public class EasyStreamTest { public Student() { // this is an accessible parameterless constructor. } - - public Boolean getMatchParent() { - return BooleanUtil.isTrue(matchParent); - } } @Test From 9354d1c74aa342877f0e64762927f7e1bd3b3300 Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Mon, 19 Sep 2022 11:28:09 +0800 Subject: [PATCH 08/16] =?UTF-8?q?:trollface:=20=E6=BC=8F=E6=8E=89=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=B8=AAfinal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/hutool/core/stream/CollectorUtil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index 9b9e483dc..4816b27d3 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -444,7 +444,7 @@ public class CollectorUtil { final Function pIdGetter, final BiConsumer> childrenSetter, final Predicate parentPredicate, - boolean isParallel) { + final boolean isParallel) { List parents = new ArrayList<>(); return Collectors.collectingAndThen(groupingBy(pIdGetter, new SimpleCollector<>(ArrayList::new, @@ -479,7 +479,7 @@ public class CollectorUtil { final Function idGetter, final Function>, List> parentFactory, final BiConsumer> childrenSetter, - boolean isParallel) { + final boolean isParallel) { return pIdValuesMap -> { final MutableObj>> recursiveRef = new MutableObj<>(); final Consumer> recursive = parents -> EasyStream.of(parents, isParallel).forEach(parent -> { From 1f6a651fefaf09134df25a545a8c5ab26cb9649b Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Mon, 19 Sep 2022 11:31:25 +0800 Subject: [PATCH 09/16] =?UTF-8?q?:trollface:=20=E6=BC=8F=E6=8E=89=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=B8=AAfinal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/hutool/core/stream/CollectorUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index 4816b27d3..193a18645 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -445,7 +445,7 @@ public class CollectorUtil { final BiConsumer> childrenSetter, final Predicate parentPredicate, final boolean isParallel) { - List parents = new ArrayList<>(); + final List parents = new ArrayList<>(); return Collectors.collectingAndThen(groupingBy(pIdGetter, new SimpleCollector<>(ArrayList::new, (acc, e) -> { From d9d3c39d4e5058c08fb0638bf87806273e39957f Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Mon, 19 Sep 2022 11:31:39 +0800 Subject: [PATCH 10/16] =?UTF-8?q?:trollface:=20=E6=BC=8F=E6=8E=89=E4=BA=86?= =?UTF-8?q?=E4=B8=80=E4=B8=AAfinal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/cn/hutool/core/stream/CollectorUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index 193a18645..29c485a49 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -487,7 +487,7 @@ public class CollectorUtil { childrenSetter.accept(parent, children); recursiveRef.get().accept(children); }); - List parents = parentFactory.apply(pIdValuesMap); + final List parents = parentFactory.apply(pIdValuesMap); if (!parents.isEmpty()) { recursiveRef.set(recursive); recursiveRef.get().accept(parents); From e81585d7d0b845bc837ba1c7a9213b31537701de Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Mon, 19 Sep 2022 11:50:18 +0800 Subject: [PATCH 11/16] :trollface: false --- .../src/main/java/cn/hutool/core/stream/CollectorUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index 29c485a49..35d3ecc8c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -488,7 +488,7 @@ public class CollectorUtil { recursiveRef.get().accept(children); }); final List parents = parentFactory.apply(pIdValuesMap); - if (!parents.isEmpty()) { + if (false == parents.isEmpty()) { recursiveRef.set(recursive); recursiveRef.get().accept(parents); } From 0dda333b07f5464577276ff8762ee780b19b1ac6 Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Mon, 19 Sep 2022 11:53:58 +0800 Subject: [PATCH 12/16] =?UTF-8?q?:trollface:=20=E9=80=92=E5=BD=92=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=E9=81=8D=E5=8E=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/core/stream/CollectorUtil.java | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index 35d3ecc8c..e2b3e1f9d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -1,7 +1,6 @@ package cn.hutool.core.stream; import cn.hutool.core.lang.Opt; -import cn.hutool.core.lang.mutable.MutableObj; import cn.hutool.core.text.StrUtil; import cn.hutool.core.util.ArrayUtil; @@ -481,18 +480,14 @@ public class CollectorUtil { final BiConsumer> childrenSetter, final boolean isParallel) { return pIdValuesMap -> { - final MutableObj>> recursiveRef = new MutableObj<>(); - final Consumer> recursive = parents -> EasyStream.of(parents, isParallel).forEach(parent -> { - final List children = pIdValuesMap.get(idGetter.apply(parent)); - childrenSetter.accept(parent, children); - recursiveRef.get().accept(children); - }); - final List parents = parentFactory.apply(pIdValuesMap); - if (false == parents.isEmpty()) { - recursiveRef.set(recursive); - recursiveRef.get().accept(parents); - } - return parents; + EasyStream.of(pIdValuesMap.values(), isParallel).flat(Function.identity()) + .forEach(value -> { + final List children = pIdValuesMap.get(idGetter.apply(value)); + if (children != null) { + childrenSetter.accept(value, children); + } + }); + return parentFactory.apply(pIdValuesMap); }; } From c4e20d91849e4fc8e6df3b977d28710c6b0f206d Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Mon, 19 Sep 2022 11:55:53 +0800 Subject: [PATCH 13/16] =?UTF-8?q?:trollface:=20=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/cn/hutool/core/stream/CollectorUtil.java | 8 ++++---- .../src/main/java/cn/hutool/core/stream/EasyStream.java | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index e2b3e1f9d..b6b7c158c 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -370,7 +370,7 @@ public class CollectorUtil { } /** - *

将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点,内置一个递归,注意内存开销 + *

将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点 * 因为需要在当前传入数据里查找,所以这是一个结束操作
* * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} @@ -394,7 +394,7 @@ public class CollectorUtil { } /** - *

将集合转换为树,默认用 {@code parentId == pidValue} 来判断树的根节点,可以为null,内置一个递归,注意内存开销 + *

将集合转换为树,默认用 {@code parentId == pidValue} 来判断树的根节点,可以为null * 因为需要在当前传入数据里查找,所以这是一个结束操作
* * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} @@ -421,7 +421,7 @@ public class CollectorUtil { } /** - * 将集合转换为树,自定义根节点的判断条件,内置一个递归,注意内存开销 + * 将集合转换为树,自定义根节点的判断条件 * 因为需要在当前传入数据里查找,所以这是一个结束操作 * * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} @@ -462,7 +462,7 @@ public class CollectorUtil { } /** - * toTree的内联函数,内置一个小递归(没错,lambda可以写递归) + * toTree的内联函数 * 因为需要在当前传入数据里查找,所以这是一个结束操作 * * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index 9b77b1cf5..1fea0642d 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -265,7 +265,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点,内置一个递归,注意内存开销 + *

将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点 * 因为需要在当前传入数据里查找,所以这是一个结束操作
* * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} @@ -288,7 +288,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream Date: Mon, 19 Sep 2022 11:56:52 +0800 Subject: [PATCH 14/16] :trollface: javadoc --- .../src/main/java/cn/hutool/core/stream/CollectorUtil.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index b6b7c158c..d318bd852 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -399,6 +399,7 @@ public class CollectorUtil { * * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} + * @param pidValue pid的值 * @param childrenSetter children的setter对应的lambda,可以写作{ @code Student::setChildren} * @param isParallel 是否并行去组装,数据量特别大时使用 * @param 此处是元素类型 @@ -428,6 +429,7 @@ public class CollectorUtil { * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} * @param childrenSetter children的setter对应的lambda,可以写作 {@code Student::setChildren} * @param parentPredicate 树顶部的判断条件,可以写作 {@code s -> Objects.equals(s.getParentId(),0L) } + * @param isParallel 是否并行处理 * @param 此处是元素类型 * @param 此处是id、parentId的泛型限制 * @return list 组装好的树
From e924b77fb8ad3f4c03a199864618f7230dd49dc2 Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Tue, 20 Sep 2022 09:58:05 +0800 Subject: [PATCH 15/16] =?UTF-8?q?:trollface:=20=E6=8A=BD=E5=8F=96=E5=88=B0?= =?UTF-8?q?TerminableWrappedStream=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/hutool/core/stream/CollectorUtil.java | 4 +- .../cn/hutool/core/stream/EasyStream.java | 48 --- .../core/stream/TerminableWrappedStream.java | 351 ++++++++++-------- 3 files changed, 203 insertions(+), 200 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java index d318bd852..1dcc72096 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -453,7 +453,9 @@ public class CollectorUtil { if (parentPredicate.test(e)) { parents.add(e); } - acc.add(e); + if (idGetter.apply(e) != null) { + acc.add(e); + } }, (left, right) -> { left.addAll(right); diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java index 1fea0642d..b892b7199 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/EasyStream.java @@ -264,54 +264,6 @@ public class EasyStream extends AbstractEnhancedWrappedStream(stream); } - /** - *

将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点 - * 因为需要在当前传入数据里查找,所以这是一个结束操作
- * - * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} - * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} - * @param childrenSetter children的setter对应的lambda,可以写作{ @code Student::setChildren} - * @param 此处是id、parentId的泛型限制 - * @return list 组装好的树
- * eg: - *

{@code
-	 * List studentTree = EasyStream.of(students).
-	 * 	toTree(Student::getId, Student::getParentId, Student::setChildren);
-	 * }
- * @author VampireAchao - */ - public > List toTree( - final Function idGetter, - final Function pIdGetter, - final BiConsumer> childrenSetter) { - return collect(CollectorUtil.toTree(idGetter, pIdGetter, childrenSetter, isParallel())); - } - - /** - * 将集合转换为树,自定义根节点的判断条件 - * 因为需要在当前传入数据里查找,所以这是一个结束操作 - * - * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} - * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} - * @param childrenSetter children的setter对应的lambda,可以写作 {@code Student::setChildren} - * @param parentPredicate 树顶部的判断条件,可以写作 {@code s -> Objects.equals(s.getParentId(),0L) } - * @param 此处是id、parentId的泛型限制 - * @return list 组装好的树
- * eg: - *
{@code
-	 * List studentTree = EasyStream.of(students).
-	 * 	.toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent);
-	 * }
- * @author VampireAchao - */ - public > List toTree( - final Function idGetter, - final Function pIdGetter, - final BiConsumer> childrenSetter, - final Predicate parentPredicate) { - return collect(CollectorUtil.toTree(idGetter, pIdGetter, childrenSetter, parentPredicate, isParallel())); - } - /** * 建造者 * diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/TerminableWrappedStream.java b/hutool-core/src/main/java/cn/hutool/core/stream/TerminableWrappedStream.java index e329f9901..19958f0c4 100644 --- a/hutool-core/src/main/java/cn/hutool/core/stream/TerminableWrappedStream.java +++ b/hutool-core/src/main/java/cn/hutool/core/stream/TerminableWrappedStream.java @@ -22,47 +22,47 @@ import java.util.stream.Stream; */ public interface TerminableWrappedStream> extends WrappedStream { - // region ============ to collection ============ + // region ============ to collection ============ - /** - * 转换为{@link ArrayList} - * - * @return 集合 - * @see #toColl(Supplier) - */ - default List toList() { - return this.toColl(ArrayList::new); - } - - /** - * 换为不可变集合 - * - * @return 集合 + /** + * 转换为{@link ArrayList} + * + * @return 集合 * @see #toColl(Supplier) */ - default List toUnmodifiableList() { - return Collections.unmodifiableList(this.toList()); - } + default List toList() { + return this.toColl(ArrayList::new); + } - /** - * 转换为HashSet - * - * @return 集合 + /** + * 换为不可变集合 + * + * @return 集合 * @see #toColl(Supplier) */ - default Set toSet() { - return this.toColl(HashSet::new); - } + default List toUnmodifiableList() { + return Collections.unmodifiableList(this.toList()); + } - /** - * 换为不可变集合 - * - * @return 集合 + /** + * 转换为HashSet + * + * @return 集合 * @see #toColl(Supplier) */ - default Set toUnmodifiableSet() { - return Collections.unmodifiableSet(this.toSet()); - } + default Set toSet() { + return this.toColl(HashSet::new); + } + + /** + * 换为不可变集合 + * + * @return 集合 + * @see #toColl(Supplier) + */ + default Set toUnmodifiableSet() { + return Collections.unmodifiableSet(this.toSet()); + } /** * 转换成集合 @@ -76,103 +76,103 @@ public interface TerminableWrappedStream key类型 - * @return map + /** + * 转换为map,key为给定操作执行后的返回值,value为当前元素 + * + * @param keyMapper 指定的key操作 + * @param key类型 + * @return map * @see #toMap(Function, Function, BinaryOperator, Supplier) - */ - default Map toMap(final Function keyMapper) { - return this.toMap(keyMapper, Function.identity()); - } + */ + default Map toMap(final Function keyMapper) { + return this.toMap(keyMapper, Function.identity()); + } - /** - * 转换为map,key,value为给定操作执行后的返回值 - * - * @param keyMapper 指定的key操作 - * @param valueMapper 指定value操作 - * @param key类型 - * @param value类型 - * @return map + /** + * 转换为map,key,value为给定操作执行后的返回值 + * + * @param keyMapper 指定的key操作 + * @param valueMapper 指定value操作 + * @param key类型 + * @param value类型 + * @return map * @see #toMap(Function, Function, BinaryOperator, Supplier) - */ - default Map toMap( - final Function keyMapper, final Function valueMapper) { - return this.toMap(keyMapper, valueMapper, (l, r) -> r); - } + */ + default Map toMap( + final Function keyMapper, final Function valueMapper) { + return this.toMap(keyMapper, valueMapper, (l, r) -> r); + } - /** - * 转换为不可变map,key,value为给定操作执行后的返回值 - * - * @param keyMapper 指定的key操作 - * @param valueMapper 指定value操作 - * @param key类型 - * @param value类型 - * @return map + /** + * 转换为不可变map,key,value为给定操作执行后的返回值 + * + * @param keyMapper 指定的key操作 + * @param valueMapper 指定value操作 + * @param key类型 + * @param value类型 + * @return map * @see #toMap(Function, Function, BinaryOperator, Supplier) - */ - default Map toUnmodifiableMap( - final Function keyMapper, final Function valueMapper) { - return Collections.unmodifiableMap(this.toMap(keyMapper, valueMapper)); - } + */ + default Map toUnmodifiableMap( + final Function keyMapper, final Function valueMapper) { + return Collections.unmodifiableMap(this.toMap(keyMapper, valueMapper)); + } - /** - * 转换为map,key,value为给定操作执行后的返回值 - * - * @param keyMapper 指定的key操作 - * @param valueMapper 指定value操作 - * @param mergeFunction 合并操作 - * @param key类型 - * @param value类型 - * @return map + /** + * 转换为map,key,value为给定操作执行后的返回值 + * + * @param keyMapper 指定的key操作 + * @param valueMapper 指定value操作 + * @param mergeFunction 合并操作 + * @param key类型 + * @param value类型 + * @return map * @see #toMap(Function, Function, BinaryOperator, Supplier) - */ - default Map toMap( - final Function keyMapper, - final Function valueMapper, - final BinaryOperator mergeFunction) { - return this.toMap(keyMapper, valueMapper, mergeFunction, HashMap::new); - } + */ + default Map toMap( + final Function keyMapper, + final Function valueMapper, + final BinaryOperator mergeFunction) { + return this.toMap(keyMapper, valueMapper, mergeFunction, HashMap::new); + } - /** - * 转换为不可变map,key,value为给定操作执行后的返回值 - * - * @param keyMapper 指定的key操作 - * @param valueMapper 指定value操作 - * @param mergeFunction 合并操作 - * @param key类型 - * @param value类型 - * @return map + /** + * 转换为不可变map,key,value为给定操作执行后的返回值 + * + * @param keyMapper 指定的key操作 + * @param valueMapper 指定value操作 + * @param mergeFunction 合并操作 + * @param key类型 + * @param value类型 + * @return map * @see #toMap(Function, Function, BinaryOperator, Supplier) - */ - default Map toUnmodifiableMap( - final Function keyMapper, - final Function valueMapper, - final BinaryOperator mergeFunction) { - return Collections.unmodifiableMap( - this.toMap(keyMapper, valueMapper, mergeFunction, HashMap::new) + */ + default Map toUnmodifiableMap( + final Function keyMapper, + final Function valueMapper, + final BinaryOperator mergeFunction) { + return Collections.unmodifiableMap( + this.toMap(keyMapper, valueMapper, mergeFunction, HashMap::new) ); - } + } - /** - * 转换为map,key,value为给定操作执行后的返回值 - * - * @param keyMapper 指定的key操作 - * @param valueMapper 指定value操作 - * @param mergeFunction 合并操作 - * @param mapSupplier map工厂 - * @param key类型 - * @param value类型 - * @param map类型 - * @return map - */ - default > M toMap( + /** + * 转换为map,key,value为给定操作执行后的返回值 + * + * @param keyMapper 指定的key操作 + * @param valueMapper 指定value操作 + * @param mergeFunction 合并操作 + * @param mapSupplier map工厂 + * @param key类型 + * @param value类型 + * @param map类型 + * @return map + */ + default > M toMap( final Function keyMapper, final Function valueMapper, final BinaryOperator mergeFunction, @@ -181,40 +181,89 @@ public interface TerminableWrappedStream将集合转换为树,默认用 {@code parentId == null} 来判断树的根节点 + * 因为需要在当前传入数据里查找,所以这是一个结束操作
+ * + * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} + * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} + * @param childrenSetter children的setter对应的lambda,可以写作{ @code Student::setChildren} + * @param 此处是id、parentId的泛型限制 + * @return list 组装好的树
+ * eg: + *
{@code
+	 * List studentTree = EasyStream.of(students).
+	 * 	toTree(Student::getId, Student::getParentId, Student::setChildren);
+	 * }
+ * @author VampireAchao + */ + default > List toTree( + final Function idGetter, + final Function pIdGetter, + final BiConsumer> childrenSetter) { + return collect(CollectorUtil.toTree(idGetter, pIdGetter, childrenSetter, isParallel())); + } - // region ============ to zip ============ + /** + * 将集合转换为树,自定义根节点的判断条件 + * 因为需要在当前传入数据里查找,所以这是一个结束操作 + * + * @param idGetter id的getter对应的lambda,可以写作 {@code Student::getId} + * @param pIdGetter parentId的getter对应的lambda,可以写作 {@code Student::getParentId} + * @param childrenSetter children的setter对应的lambda,可以写作 {@code Student::setChildren} + * @param parentPredicate 树顶部的判断条件,可以写作 {@code s -> Objects.equals(s.getParentId(),0L) } + * @param 此处是id、parentId的泛型限制 + * @return list 组装好的树
+ * eg: + *
{@code
+	 * List studentTree = EasyStream.of(students).
+	 * 	.toTree(Student::getId, Student::getParentId, Student::setChildren, Student::getMatchParent);
+	 * }
+ * @author VampireAchao + */ + default > List toTree( + final Function idGetter, + final Function pIdGetter, + final BiConsumer> childrenSetter, + final Predicate parentPredicate) { + return collect(CollectorUtil.toTree(idGetter, pIdGetter, childrenSetter, parentPredicate, isParallel())); + } - /** - * 与给定的可迭代对象转换成map,key为现有元素,value为给定可迭代对象迭代的元素
- * 至少包含全部的key,如果对应位置上的value不存在,则为null - * - * @param other 可迭代对象 - * @param 可迭代对象迭代的元素类型 - * @return map,key为现有元素,value为给定可迭代对象迭代的元素;
- * 至少包含全部的key,如果对应位置上的value不存在,则为null;
- * 如果key重复, 则保留最后一个关联的value;
- */ - default Map toZip(final Iterable other) { + + // endregion + + // region ============ to zip ============ + + /** + * 与给定的可迭代对象转换成map,key为现有元素,value为给定可迭代对象迭代的元素
+ * 至少包含全部的key,如果对应位置上的value不存在,则为null + * + * @param other 可迭代对象 + * @param 可迭代对象迭代的元素类型 + * @return map,key为现有元素,value为给定可迭代对象迭代的元素;
+ * 至少包含全部的key,如果对应位置上的value不存在,则为null;
+ * 如果key重复, 则保留最后一个关联的value;
+ */ + default Map toZip(final Iterable other) { Objects.requireNonNull(other); - // value对象迭代器 - final Iterator iterator = Opt.ofNullable(other).map(Iterable::iterator).orElseGet(Collections::emptyIterator); - if (this.isParallel()) { + // value对象迭代器 + final Iterator iterator = Opt.ofNullable(other).map(Iterable::iterator).orElseGet(Collections::emptyIterator); + if (this.isParallel()) { final List keyList = toList(); - final Map map = new HashMap<>(keyList.size()); - for (final T key : keyList) { - map.put(key, iterator.hasNext() ? iterator.next() : null); - } - return map; - } else { - return this.toMap(Function.identity(), e -> iterator.hasNext() ? iterator.next() : null); - } - } + final Map map = new HashMap<>(keyList.size()); + for (final T key : keyList) { + map.put(key, iterator.hasNext() ? iterator.next() : null); + } + return map; + } else { + return this.toMap(Function.identity(), e -> iterator.hasNext() ? iterator.next() : null); + } + } - // endregion + // endregion // region ============ to optional ============ @@ -408,7 +457,7 @@ public interface TerminableWrappedStream Map group( - final Function classifier, final Collector downstream) { + final Function classifier, final Collector downstream) { return this.group(classifier, HashMap::new, downstream); } @@ -426,9 +475,9 @@ public interface TerminableWrappedStream> M group( - final Function classifier, - final Supplier mapFactory, - final Collector downstream) { + final Function classifier, + final Supplier mapFactory, + final Collector downstream) { Objects.requireNonNull(classifier); Objects.requireNonNull(mapFactory); Objects.requireNonNull(downstream); @@ -449,8 +498,8 @@ public interface TerminableWrappedStream 值类型 - * @param predicate 判断条件 + * @param 值类型 + * @param predicate 判断条件 * @param collFactory 提供的集合 * @return map * @see #partition(Predicate, Collector) @@ -464,7 +513,7 @@ public interface TerminableWrappedStream 返回值类型 + * @param 返回值类型 * @return map */ default Map partition(final Predicate predicate, final Collector downstream) { From 463539f826903a3b164a50613c73d2307853e21f Mon Sep 17 00:00:00 2001 From: VampireAchao Date: Tue, 20 Sep 2022 10:14:37 +0800 Subject: [PATCH 16/16] =?UTF-8?q?:trollface:=20=E8=B0=83=E6=95=B4=E9=83=A8?= =?UTF-8?q?=E5=88=86=E6=B5=8B=E8=AF=95=E7=94=A8=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stream/AbstractEnhancedWrappedStreamTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/AbstractEnhancedWrappedStreamTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/AbstractEnhancedWrappedStreamTest.java index 8935a75ad..be03d08bd 100644 --- a/hutool-core/src/test/java/cn/hutool/core/stream/AbstractEnhancedWrappedStreamTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/stream/AbstractEnhancedWrappedStreamTest.java @@ -40,7 +40,7 @@ public class AbstractEnhancedWrappedStreamTest { @Test public void testToSet() { final List list = asList(1, 2, 3); - Set toSet = wrap(list).map(String::valueOf).toSet(); + final Set toSet = wrap(list).map(String::valueOf).toSet(); Assert.assertEquals(new HashSet<>(asList("1", "2", "3")), toSet); } @@ -636,7 +636,7 @@ public class AbstractEnhancedWrappedStreamTest { List zip = wrap(orders).zip(list, (e1, e2) -> e1 + "." + e2).toList(); Assert.assertEquals(Arrays.asList("1.dromara", "2.hutool", "3.sweet"), zip); - zip = wrap((Stream) EasyStream.iterate(1, i -> i + 1)).limit(10).zip(list, (e1, e2) -> e1 + "." + e2).toList(); + zip = this.wrap((Stream)EasyStream.iterate(1, i -> i + 1)).limit(10).zip(list, (e1, e2) -> e1 + "." + e2).toList(); Assert.assertEquals(Arrays.asList("1.dromara", "2.hutool", "3.sweet"), zip); } @@ -663,15 +663,15 @@ public class AbstractEnhancedWrappedStreamTest { } @SafeVarargs - private static Wrapper wrap(T... array) { + private final Wrapper wrap(final T... array) { return new Wrapper<>(Stream.of(array)); } - private static Wrapper wrap(Iterable iterable) { + private Wrapper wrap(final Iterable iterable) { return new Wrapper<>(StreamSupport.stream(iterable.spliterator(), false)); } - private static Wrapper wrap(Stream stream) { + private Wrapper wrap(final Stream stream) { return new Wrapper<>(stream); } @@ -683,12 +683,12 @@ public class AbstractEnhancedWrappedStreamTest { * @param stream 包装的流对象 * @throws NullPointerException 当{@code unwrap}为{@code null}时抛出 */ - protected Wrapper(Stream stream) { + protected Wrapper(final Stream stream) { super(stream); } @Override - public Wrapper wrap(Stream source) { + public Wrapper wrap(final Stream source) { return new Wrapper<>(source); }