添加支持对流进行转换的收集器

This commit is contained in:
huangchengxing 2022-08-30 15:04:30 +08:00
parent 9e20dbb7a0
commit 4893a5e9aa
2 changed files with 107 additions and 46 deletions

View File

@ -4,15 +4,7 @@ import cn.hutool.core.lang.Opt;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ArrayUtil;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.List;
import java.util.ArrayList;
import java.util.Objects;
import java.util.StringJoiner;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
@ -32,7 +24,7 @@ public class CollectorUtil {
* 说明已包含IDENTITY_FINISH特征 Characteristics.IDENTITY_FINISH 的缩写
*/
public static final Set<Collector.Characteristics> CH_ID
= Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
= Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
/**
* 说明不包含IDENTITY_FINISH特征
*/
@ -58,7 +50,7 @@ public class CollectorUtil {
* @return {@link Collector}
*/
public static <T> Collector<T, ?, String> joining(final CharSequence delimiter,
final Function<T, ? extends CharSequence> toStringFunc) {
final Function<T, ? extends CharSequence> toStringFunc) {
return joining(delimiter, StrUtil.EMPTY, StrUtil.EMPTY, toStringFunc);
}
@ -73,15 +65,15 @@ public class CollectorUtil {
* @return {@link Collector}
*/
public static <T> Collector<T, ?, String> joining(final CharSequence delimiter,
final CharSequence prefix,
final CharSequence suffix,
final Function<T, ? extends CharSequence> toStringFunc) {
final CharSequence prefix,
final CharSequence suffix,
final Function<T, ? extends CharSequence> toStringFunc) {
return new SimpleCollector<>(
() -> new StringJoiner(delimiter, prefix, suffix),
(joiner, ele) -> joiner.add(toStringFunc.apply(ele)),
StringJoiner::merge,
StringJoiner::toString,
Collections.emptySet()
() -> new StringJoiner(delimiter, prefix, suffix),
(joiner, ele) -> joiner.add(toStringFunc.apply(ele)),
StringJoiner::merge,
StringJoiner::toString,
Collections.emptySet()
);
}
@ -100,8 +92,8 @@ public class CollectorUtil {
* @return {@link Collector}
*/
public static <T, K, D, A, M extends Map<K, D>> Collector<T, ?, M> groupingBy(final Function<? super T, ? extends K> classifier,
final Supplier<M> mapFactory,
final Collector<? super T, A, D> downstream) {
final Supplier<M> mapFactory,
final Collector<? super T, A, D> downstream) {
final Supplier<A> downstreamSupplier = downstream.supplier();
final BiConsumer<A, ? super T> downstreamAccumulator = downstream.accumulator();
final BiConsumer<Map<K, A>, T> accumulator = (m, t) -> {
@ -141,7 +133,7 @@ public class CollectorUtil {
*/
public static <T, K, A, D>
Collector<T, ?, Map<K, D>> groupingBy(final Function<? super T, ? extends K> classifier,
final Collector<? super T, A, D> downstream) {
final Collector<? super T, A, D> downstream) {
return groupingBy(classifier, HashMap::new, downstream);
}
@ -171,8 +163,8 @@ public class CollectorUtil {
*/
public static <T, K, U>
Collector<T, ?, Map<K, U>> toMap(final Function<? super T, ? extends K> keyMapper,
final Function<? super T, ? extends U> valueMapper,
final BinaryOperator<U> mergeFunction) {
final Function<? super T, ? extends U> valueMapper,
final BinaryOperator<U> mergeFunction) {
return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
}
@ -191,11 +183,11 @@ public class CollectorUtil {
*/
public static <T, K, U, M extends Map<K, U>>
Collector<T, ?, M> toMap(final Function<? super T, ? extends K> keyMapper,
final Function<? super T, ? extends U> valueMapper,
final BinaryOperator<U> mergeFunction,
final Supplier<M> mapSupplier) {
final Function<? super T, ? extends U> valueMapper,
final BinaryOperator<U> mergeFunction,
final Supplier<M> mapSupplier) {
final BiConsumer<M, T> accumulator
= (map, element) -> map.put(Opt.ofNullable(element).map(keyMapper).get(), Opt.ofNullable(element).map(valueMapper).get());
= (map, element) -> map.put(Opt.ofNullable(element).map(keyMapper).get(), Opt.ofNullable(element).map(valueMapper).get());
return new SimpleCollector<>(mapSupplier, accumulator, mapMerger(mergeFunction), CH_ID);
}
@ -241,15 +233,67 @@ public class CollectorUtil {
*/
public static <K, V, R extends Map<K, List<V>>> Collector<Map<K, V>, ?, R> reduceListMap(final Supplier<R> mapSupplier) {
return Collectors.reducing(mapSupplier.get(), value -> {
R result = mapSupplier.get();
value.forEach((k, v) -> result.computeIfAbsent(k, i -> new ArrayList<>()).add(v));
return result;
}, (l, r) -> {
r.forEach((k, v) -> l.computeIfAbsent(k, i -> new ArrayList<>()).addAll(v));
return l;
}
R result = mapSupplier.get();
value.forEach((k, v) -> result.computeIfAbsent(k, i -> new ArrayList<>()).add(v));
return result;
}, (l, r) -> {
r.forEach((k, v) -> l.computeIfAbsent(k, i -> new ArrayList<>()).addAll(v));
return l;
}
);
}
/**
* 将流转为{@link EasyStream}
*
* @param <T> 输入元素类型
* @return 收集器
*/
public static <T> Collector<T, ?, EasyStream<T>> toEasyStream() {
return transform(ArrayList::new, EasyStream::of);
}
/**
* 收集元素将其转为指定{@link Collection}集合后再对该集合进行转换并最终返回转换后的结果
* 返回的收集器的效果等同于
* <pre>{@code
* Collection<T> coll = Stream.of(a, b, c, d)
* .collect(Collectors.toCollection(collFactory));
* R result = mapper.apply(coll);
* }</pre>
*
* @param collFactory 中间收集输入元素的集合的创建方法
* @param mapper 最终将元素集合映射为返回值的方法
* @param <R> 返回值类型
* @param <T> 输入元素类型
* @param <C> 中间收集输入元素的集合类型
* @return 收集器
*/
public static <T, R, C extends Collection<T>> Collector<T, C, R> transform(
Supplier<C> collFactory, Function<C, R> mapper) {
Objects.requireNonNull(collFactory);
Objects.requireNonNull(mapper);
return new SimpleCollector<>(
collFactory, C::add, (l1, l2) -> { l1.addAll(l2); return l1; }, mapper, CH_NOID
);
}
/**
* 收集元素将其转为{@link ArrayList}集合后再对该集合进行转换并最终返回转换后的结果
* 返回的收集器的效果等同于
* <pre>{@code
* List<T> coll = Stream.of(a, b, c, d)
* .collect(Collectors.toList());
* R result = mapper.apply(coll);
* }</pre>
*
* @param mapper 最终将元素集合映射为返回值的方法
* @param <R> 返回值类型
* @param <T> 输入元素类型
* @return 收集器
*/
public static <T, R> Collector<T, List<T>, R> transform(Function<List<T>, R> mapper) {
return transform(ArrayList::new, mapper);
}
}

View File

@ -4,11 +4,9 @@ import cn.hutool.core.map.MapUtil;
import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* CollectorUtilTest
@ -21,17 +19,36 @@ public class CollectorUtilTest {
@Test
public void reduceListMapTest() {
final Set<Map<String, Integer>> nameScoreMapList = StreamUtil.of(
// 集合内的第一个map包含两个key value
MapUtil.builder("苏格拉底", 1).put("特拉叙马霍斯", 3).build(),
MapUtil.of("苏格拉底", 2),
MapUtil.of("特拉叙马霍斯", 1),
MapUtil.of("特拉叙马霍斯", 2)
// 集合内的第一个map包含两个key value
MapUtil.builder("苏格拉底", 1).put("特拉叙马霍斯", 3).build(),
MapUtil.of("苏格拉底", 2),
MapUtil.of("特拉叙马霍斯", 1),
MapUtil.of("特拉叙马霍斯", 2)
).collect(Collectors.toSet());
// 执行聚合
final Map<String, List<Integer>> nameScoresMap = nameScoreMapList.stream().collect(CollectorUtil.reduceListMap());
Assert.assertEquals(MapUtil.builder("苏格拉底", Arrays.asList(1, 2))
.put("特拉叙马霍斯", Arrays.asList(3, 1, 2)).build(),
nameScoresMap);
.put("特拉叙马霍斯", Arrays.asList(3, 1, 2)).build(),
nameScoresMap);
}
@Test
public void testTransform() {
Stream<Integer> stream = Stream.of(1, 2, 3, 4)
.collect(CollectorUtil.transform(EasyStream::of));
Assert.assertEquals(EasyStream.class, stream.getClass());
stream = Stream.of(1, 2, 3, 4)
.collect(CollectorUtil.transform(HashSet::new, EasyStream::of));
Assert.assertEquals(EasyStream.class, stream.getClass());
}
@Test
public void testToEasyStream() {
Stream<Integer> stream =Stream.of(1, 2, 3, 4)
.collect(CollectorUtil.toEasyStream());
Assert.assertEquals(EasyStream.class, stream.getClass());
}
}