From b0e62df7c6d36648b1544bfb8fa246b2071dc4d5 Mon Sep 17 00:00:00 2001 From: Looly Date: Mon, 7 Jun 2021 18:46:24 +0800 Subject: [PATCH] add Stream utils --- CHANGELOG.md | 3 +- .../cn/hutool/core/stream/CollectorUtil.java | 64 ++++++++++ .../hutool/core/stream/SimpleCollector.java | 109 ++++++++++++++++++ .../cn/hutool/core/stream/StreamUtil.java | 93 +++++++++++++++ .../cn/hutool/core/stream/package-info.java | 7 ++ .../cn/hutool/core/stream/StreamUtilTest.java | 16 +++ 6 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/stream/SimpleCollector.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/stream/StreamUtil.java create mode 100644 hutool-core/src/main/java/cn/hutool/core/stream/package-info.java create mode 100644 hutool-core/src/test/java/cn/hutool/core/stream/StreamUtilTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index d03f4cb90..d319b1a10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ------------------------------------------------------------------------------------------------------------- -# 5.6.7 (2021-06-06) +# 5.6.7 (2021-06-07) ### 🐣新特性 * 【core 】 CharSequenceUtil增加join重载(issue#I3TFJ5@Gitee) @@ -12,6 +12,7 @@ * 【core 】 改进TreeUtil.buid算法性能(pr#1594@Github) * 【core 】 CsvConfig的setXXX返回this(issue#I3UIQF@Gitee) * 【all 】 增加jmh基准测试 +* 【core 】 增加StreamUtil和CollectorUtil ### 🐞Bug修复 * 【core 】 修复FileUtil.normalize去掉末尾空格问题(issue#1603@Github) 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 new file mode 100644 index 000000000..58b03d2ba --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/stream/CollectorUtil.java @@ -0,0 +1,64 @@ +package cn.hutool.core.stream; + +import cn.hutool.core.util.StrUtil; + +import java.util.Collections; +import java.util.StringJoiner; +import java.util.function.Function; +import java.util.stream.Collector; + +/** + * 可变的汇聚操作{@link Collector} 相关工具封装 + * + * @author looly + * @since 5.6.7 + */ +public class CollectorUtil { + + /** + * 提供任意对象的Join操作的{@link Collector}实现,对象默认调用toString方法 + * + * @param delimiter 分隔符 + * @param 对象类型 + * @return {@link Collector} + */ + public static Collector joining(CharSequence delimiter) { + return joining(delimiter, Object::toString); + } + + /** + * 提供任意对象的Join操作的{@link Collector}实现 + * + * @param delimiter 分隔符 + * @param toStringFunc 自定义指定对象转换为字符串的方法 + * @param 对象类型 + * @return {@link Collector} + */ + public static Collector joining(CharSequence delimiter, + Function toStringFunc) { + return joining(delimiter, StrUtil.EMPTY, StrUtil.EMPTY, toStringFunc); + } + + /** + * 提供任意对象的Join操作的{@link Collector}实现 + * + * @param delimiter 分隔符 + * @param prefix 前缀 + * @param suffix 后缀 + * @param toStringFunc 自定义指定对象转换为字符串的方法 + * @param 对象类型 + * @return {@link Collector} + */ + public static Collector joining(CharSequence delimiter, + CharSequence prefix, + CharSequence suffix, + Function toStringFunc) { + return new SimpleCollector<>( + () -> new StringJoiner(delimiter, prefix, suffix), + (joiner, ele) -> joiner.add(toStringFunc.apply(ele)), + StringJoiner::merge, + StringJoiner::toString, + Collections.emptySet() + ); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/SimpleCollector.java b/hutool-core/src/main/java/cn/hutool/core/stream/SimpleCollector.java new file mode 100644 index 000000000..c1c87dac6 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/stream/SimpleCollector.java @@ -0,0 +1,109 @@ +package cn.hutool.core.stream; + +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; + +/** + * 简单{@link Collector}接口实现 + * + * @param 输入数据类型 + * @param 累积结果的容器类型 + * @param 数据结果类型 + * @since 5.6.7 + */ +public class SimpleCollector implements Collector { + /** + * 创建新的结果容器,容器类型为A + */ + private final Supplier supplier; + /** + * 将输入元素合并到结果容器中 + */ + private final BiConsumer accumulator; + /** + * 合并两个结果容器(并行流使用,将多个线程产生的结果容器合并) + */ + private final BinaryOperator combiner; + /** + * 将结果容器转换成最终的表示 + */ + private final Function finisher; + /** + * 特征值枚举,见{@link Characteristics} + *
    + *
  • CONCURRENT: 表示结果容器只有一个(即使是在并行流的情况下)。 + * 只有在并行流且收集器不具备此特性的情况下,combiner()返回的lambda表达式才会执行(中间结果容器只有一个就无需合并)。 + * 设置此特性时意味着多个线程可以对同一个结果容器调用,因此结果容器必须是线程安全的。
  • + *
  • UNORDERED: 表示流中的元素无序
  • + *
  • IDENTITY_FINISH:表示中间结果容器类型与最终结果类型一致。设置此特性时finiser()方法不会被调用
  • + *
+ */ + private final Set characteristics; + + /** + * 构造 + * + * @param supplier 创建新的结果容器函数 + * @param accumulator 将输入元素合并到结果容器中函数 + * @param combiner 合并两个结果容器函数(并行流使用,将多个线程产生的结果容器合并) + * @param finisher 将结果容器转换成最终的表示函数 + * @param characteristics 特征值枚举 + */ + public SimpleCollector(Supplier
supplier, + BiConsumer accumulator, + BinaryOperator combiner, + Function finisher, + Set characteristics) { + this.supplier = supplier; + this.accumulator = accumulator; + this.combiner = combiner; + this.finisher = finisher; + this.characteristics = characteristics; + } + + /** + * 构造 + * + * @param supplier 创建新的结果容器函数 + * @param accumulator 将输入元素合并到结果容器中函数 + * @param combiner 合并两个结果容器函数(并行流使用,将多个线程产生的结果容器合并) + * @param characteristics 特征值枚举 + */ + @SuppressWarnings("unchecked") + public SimpleCollector(Supplier supplier, + BiConsumer accumulator, + BinaryOperator combiner, + Set characteristics) { + this(supplier, accumulator, combiner, i -> (R) i, characteristics); + } + + @Override + public BiConsumer accumulator() { + return accumulator; + } + + @Override + public Supplier supplier() { + return supplier; + } + + @Override + public BinaryOperator combiner() { + return combiner; + } + + @Override + public Function finisher() { + return finisher; + } + + @Override + public Set characteristics() { + return characteristics; + } + +} diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/StreamUtil.java b/hutool-core/src/main/java/cn/hutool/core/stream/StreamUtil.java new file mode 100644 index 000000000..52ebd85b1 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/stream/StreamUtil.java @@ -0,0 +1,93 @@ +package cn.hutool.core.stream; + +import cn.hutool.core.collection.CollUtil; + +import java.util.Spliterators; +import java.util.function.Function; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +/** + * {@link Stream} 工具类 + * + * @author looly + * @since 5.6.7 + */ +public class StreamUtil { + + @SafeVarargs + public static Stream of(T... values) { + if (null == values) { + return null; + } + return Stream.of(values); + } + + /** + * {@link Iterable}转换为{@link Stream},默认非并行 + * + * @param iterable 集合 + * @param 集合元素类型 + * @return {@link Stream} + */ + public static Stream of(Iterable iterable) { + return of(iterable, false); + } + + /** + * {@link Iterable}转换为{@link Stream} + * + * @param iterable 集合 + * @param parallel 是否并行 + * @param 集合元素类型 + * @return {@link Stream} + */ + public static Stream of(Iterable iterable, boolean parallel) { + if (null == iterable) { + return null; + } + return StreamSupport.stream( + Spliterators.spliterator(CollUtil.toCollection(iterable), 0), + parallel); + } + + /** + * 通过函数创建Stream + * + * @param seed 初始值 + * @param elementCreator 递进函数,每次调用此函数获取下一个值 + * @param limit 限制个数 + * @param 创建元素类型 + * @return {@link Stream} + */ + public static Stream of(T seed, UnaryOperator elementCreator, int limit) { + return Stream.iterate(seed, elementCreator).limit(limit); + } + + /** + * 将Stream中所有元素以指定分隔符,合并为一个字符串,对象默认调用toString方法 + * + * @param stream {@link Stream} + * @param delimiter 分隔符 + * @param 元素类型 + * @return 字符串 + */ + public static String join(Stream stream, CharSequence delimiter) { + return stream.collect(CollectorUtil.joining(delimiter)); + } + + /** + * 将Stream中所有元素以指定分隔符,合并为一个字符串 + * + * @param stream {@link Stream} + * @param delimiter 分隔符 + * @param toStringFunc 元素转换为字符串的函数 + * @param 元素类型 + * @return 字符串 + */ + public static String join(Stream stream, CharSequence delimiter, + Function toStringFunc) { + return stream.collect(CollectorUtil.joining(delimiter, toStringFunc)); + } +} diff --git a/hutool-core/src/main/java/cn/hutool/core/stream/package-info.java b/hutool-core/src/main/java/cn/hutool/core/stream/package-info.java new file mode 100644 index 000000000..155cf24db --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/core/stream/package-info.java @@ -0,0 +1,7 @@ +/** + * Java8的stream相关封装 + * + * @author looly + * + */ +package cn.hutool.core.stream; diff --git a/hutool-core/src/test/java/cn/hutool/core/stream/StreamUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/stream/StreamUtilTest.java new file mode 100644 index 000000000..a38d8ff26 --- /dev/null +++ b/hutool-core/src/test/java/cn/hutool/core/stream/StreamUtilTest.java @@ -0,0 +1,16 @@ +package cn.hutool.core.stream; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.stream.Stream; + +public class StreamUtilTest { + + @Test + public void ofTest(){ + final Stream stream = StreamUtil.of(2, x -> x * 2, 4); + final String result = stream.collect(CollectorUtil.joining(",")); + Assert.assertEquals("2,4,8,16", result); + } +}