diff --git a/hutool-core/src/main/java/cn/hutool/core/collection/CollStreamUtil.java b/hutool-core/src/main/java/cn/hutool/core/collection/CollStreamUtil.java
index 5f6970673..c2dff6af4 100644
--- a/hutool-core/src/main/java/cn/hutool/core/collection/CollStreamUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/collection/CollStreamUtil.java
@@ -5,16 +5,10 @@ import cn.hutool.core.lang.Opt;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.stream.StreamUtil;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
+import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
+import java.util.stream.Collector;
import java.util.stream.Collectors;
/**
@@ -55,7 +49,7 @@ public class CollStreamUtil {
if (CollUtil.isEmpty(collection)) {
return Collections.emptyMap();
}
- return toMap(collection, (v)-> Opt.ofNullable(v).map(key).get(), Function.identity(), isParallel);
+ return toMap(collection, (v) -> Opt.ofNullable(v).map(key).get(), Function.identity(), isParallel);
}
/**
@@ -94,48 +88,48 @@ public class CollStreamUtil {
/**
- * 将collection按照规则(比如有相同的班级id)分类成map
+ * 将collection按照规则(比如有相同的班级id)分组成map
* {@code Collection -------> Map> }
*
- * @param collection 需要分类的集合
- * @param key 分类的规则
+ * @param collection 需要分组的集合
+ * @param key 分组的规则
* @param collection中的泛型
* @param map中的key类型
- * @return 分类后的map
+ * @return 分组后的map
*/
public static Map> groupByKey(Collection collection, Function key) {
return groupByKey(collection, key, false);
}
/**
- * 将collection按照规则(比如有相同的班级id)分类成map
+ * 将collection按照规则(比如有相同的班级id)分组成map
* {@code Collection -------> Map> }
*
- * @param collection 需要分类的集合
- * @param key 分类的规则
+ * @param collection 需要分组的集合
+ * @param key 分组的规则
* @param isParallel 是否并行流
* @param collection中的泛型
* @param map中的key类型
- * @return 分类后的map
+ * @return 分组后的map
*/
public static Map> groupByKey(Collection collection, Function key, boolean isParallel) {
if (CollUtil.isEmpty(collection)) {
return Collections.emptyMap();
}
- return StreamUtil.of(collection, isParallel).collect(Collectors.groupingBy(key, Collectors.toList()));
+ return groupThen(collection, key, Collectors.toList(), isParallel);
}
/**
- * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map
+ * 将collection按照两个规则(比如有相同的年级id,班级id)分组成双层map
* {@code Collection ---> Map>> }
*
- * @param collection 需要分类的集合
- * @param key1 第一个分类的规则
- * @param key2 第二个分类的规则
+ * @param collection 需要分组的集合
+ * @param key1 第一个分组的规则
+ * @param key2 第二个分组的规则
* @param 集合元素类型
* @param 第一个map中的key类型
* @param 第二个map中的key类型
- * @return 分类后的map
+ * @return 分组后的map
*/
public static Map>> groupBy2Key(Collection collection, Function key1, Function key2) {
return groupBy2Key(collection, key1, key2, false);
@@ -143,76 +137,74 @@ public class CollStreamUtil {
/**
- * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map
+ * 将collection按照两个规则(比如有相同的年级id,班级id)分组成双层map
* {@code Collection ---> Map>> }
*
- * @param collection 需要分类的集合
- * @param key1 第一个分类的规则
- * @param key2 第二个分类的规则
+ * @param collection 需要分组的集合
+ * @param key1 第一个分组的规则
+ * @param key2 第二个分组的规则
* @param isParallel 是否并行流
* @param 集合元素类型
* @param 第一个map中的key类型
* @param 第二个map中的key类型
- * @return 分类后的map
+ * @return 分组后的map
*/
public static Map>> groupBy2Key(Collection collection, Function key1,
Function key2, boolean isParallel) {
if (CollUtil.isEmpty(collection)) {
return Collections.emptyMap();
}
- return StreamUtil.of(collection, isParallel)
- .collect(Collectors.groupingBy(key1, Collectors.groupingBy(key2, Collectors.toList())));
+ return groupThen(collection, key1, Collectors.groupingBy(key2, Collectors.toList()), isParallel);
}
/**
- * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map
+ * 将collection按照两个规则(比如有相同的年级id,班级id)分组成双层map
* {@code Collection ---> Map> }
*
- * @param collection 需要分类的集合
- * @param key1 第一个分类的规则
- * @param key2 第二个分类的规则
+ * @param collection 需要分组的集合
+ * @param key1 第一个分组的规则
+ * @param key2 第二个分组的规则
* @param 第一个map中的key类型
* @param 第二个map中的key类型
* @param collection中的泛型
- * @return 分类后的map
+ * @return 分组后的map
*/
public static Map> group2Map(Collection collection, Function key1, Function key2) {
return group2Map(collection, key1, key2, false);
}
/**
- * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map
+ * 将collection按照两个规则(比如有相同的年级id,班级id)分组成双层map
* {@code Collection ---> Map> }
*
- * @param collection 需要分类的集合
- * @param key1 第一个分类的规则
- * @param key2 第二个分类的规则
+ * @param collection 需要分组的集合
+ * @param key1 第一个分组的规则
+ * @param key2 第二个分组的规则
* @param isParallel 是否并行流
* @param 第一个map中的key类型
* @param 第二个map中的key类型
* @param collection中的泛型
- * @return 分类后的map
+ * @return 分组后的map
*/
public static Map> group2Map(Collection collection,
Function key1, Function key2, boolean isParallel) {
if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) {
return Collections.emptyMap();
}
- return StreamUtil.of(collection, isParallel)
- .collect(Collectors.groupingBy(key1, Collectors.toMap(key2, Function.identity(), (l, r) -> l)));
+ return groupThen(collection, key1, Collectors.toMap(key2, Function.identity(), (l, r) -> l), isParallel);
}
/**
- * 将collection按照规则(比如有相同的班级id)分类成map,map中的key为班级id,value为班级名
+ * 将collection按照规则(比如有相同的班级id)分组成map,map中的key为班级id,value为班级名
* {@code Collection -------> Map> }
*
- * @param collection 需要分类的集合
- * @param key 分类的规则
- * @param value 分类的规则
+ * @param collection 需要分组的集合
+ * @param key 分组的规则
+ * @param value 分组的规则
* @param collection中的泛型
* @param map中的key类型
* @param List中的value类型
- * @return 分类后的map
+ * @return 分组后的map
*/
public static Map> groupKeyValue(Collection collection, Function key,
Function value) {
@@ -220,25 +212,61 @@ public class CollStreamUtil {
}
/**
- * 将collection按照规则(比如有相同的班级id)分类成map,map中的key为班级id,value为班级名
+ * 将collection按照规则(比如有相同的班级id)分组成map,map中的key为班级id,value为班级名
* {@code Collection -------> Map> }
*
- * @param collection 需要分类的集合
- * @param key 分类的规则
- * @param value 分类的规则
+ * @param collection 需要分组的集合
+ * @param key 分组的规则
+ * @param value 分组的规则
* @param isParallel 是否并行流
* @param collection中的泛型
* @param map中的key类型
* @param List中的value类型
- * @return 分类后的map
+ * @return 分组后的map
*/
public static Map> groupKeyValue(Collection collection, Function key,
Function value, boolean isParallel) {
if (CollUtil.isEmpty(collection)) {
return Collections.emptyMap();
}
- return StreamUtil.of(collection, isParallel)
- .collect(Collectors.groupingBy(key, Collectors.mapping(value, Collectors.toList())));
+ return groupThen(collection, key, Collectors.mapping(value, Collectors.toList()), isParallel);
+ }
+
+ /**
+ * 作为所有groupingBy的公共方法,更接近于原生,灵活性更强
+ *
+ * @param collection 需要分组的集合
+ * @param key 第一次分组时需要的key
+ * @param downstream 分组后需要进行的操作
+ * @param collection中的泛型
+ * @param map中的key类型
+ * @param 后续操作的返回值
+ * @return 分组后的map
+ */
+ public static Map groupThen(Collection collection, Function key, Collector downstream) {
+ if (CollUtil.isEmpty(collection)) {
+ return Collections.emptyMap();
+ }
+ return groupThen(collection, key, downstream, false);
+ }
+
+ /**
+ * 作为所有groupingBy的公共方法,更接近于原生,灵活性更强
+ *
+ * @param collection 需要分组的集合
+ * @param key 第一次分组时需要的key
+ * @param downstream 分组后需要进行的操作
+ * @param isParallel 是否并行流
+ * @param collection中的泛型
+ * @param map中的key类型
+ * @param 后续操作的返回值
+ * @return 分组后的map
+ */
+ public static Map groupThen(Collection collection, Function key, Collector downstream, boolean isParallel) {
+ if (CollUtil.isEmpty(collection)) {
+ return Collections.emptyMap();
+ }
+ return StreamUtil.of(collection, isParallel).collect(Collectors.groupingBy(key, downstream));
}
/**
diff --git a/hutool-core/src/test/java/cn/hutool/core/collection/CollStreamUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/collection/CollStreamUtilTest.java
index f83f82d7f..feaa8b393 100644
--- a/hutool-core/src/test/java/cn/hutool/core/collection/CollStreamUtilTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/collection/CollStreamUtilTest.java
@@ -1,5 +1,6 @@
package cn.hutool.core.collection;
+import cn.hutool.core.map.MapUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;
@@ -7,6 +8,9 @@ import org.junit.Assert;
import org.junit.Test;
import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collector;
+import java.util.stream.Collectors;
/**
* CollectionStream测试方法
@@ -168,6 +172,39 @@ public class CollStreamUtilTest {
Assert.assertEquals(compare, map);
}
+ @Test
+ public void testGroupThen() {
+ // groupThen作为之前所有group函数的公共部分抽取出来,并更接近于jdk原生,灵活性更强
+
+ // 参数null测试
+ Map> map = CollStreamUtil.groupThen(null, Student::getTermId, Collectors.toList());
+ Assert.assertEquals(map, Collections.EMPTY_MAP);
+
+ // 参数空数组测试
+ List list = new ArrayList<>();
+ map = CollStreamUtil.groupThen(list, Student::getTermId, Collectors.toList());
+ Assert.assertEquals(map, Collections.EMPTY_MAP);
+
+ // 放入元素
+ list.add(new Student(1, 1, 1, "张三"));
+ list.add(new Student(1, 2, 1, "李四"));
+ list.add(new Student(2, 2, 1, "王五"));
+ // 先根据termId分组,再通过classId比较,找出最大值所属的那个Student,返回的Optional
+ Map> longOptionalMap = CollStreamUtil.groupThen(list, Student::getTermId, Collectors.maxBy(Comparator.comparing(Student::getClassId)));
+ Assert.assertEquals("李四", longOptionalMap.get(1L).get().getName());
+
+ // 先根据termId分组,再转换为Map
+ Map> groupThen = CollStreamUtil.groupThen(list, Student::getTermId, Collector.of(HashMap::new, (m, v) -> m.put(v.getStudentId(), v.getName()), (l, r) -> l));
+ Assert.assertEquals(
+ MapUtil.builder()
+ .put(1L, MapUtil.builder().put(1L, "李四").build())
+ .put(2L, MapUtil.builder().put(1L, "王五").build())
+ .build(),
+ groupThen);
+
+ // 总之,如果你是想要group分组后还要进行别的操作,用它就对了!
+ }
+
@Test
public void testTranslate2List() {