add Stream utils

This commit is contained in:
Looly 2021-06-07 18:46:24 +08:00
parent 6a76d260fe
commit b0e62df7c6
6 changed files with 291 additions and 1 deletions

View File

@ -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返回thisissue#I3UIQF@Gitee
* 【all 】 增加jmh基准测试
* 【core 】 增加StreamUtil和CollectorUtil
### 🐞Bug修复
* 【core 】 修复FileUtil.normalize去掉末尾空格问题issue#1603@Github

View File

@ -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 <T> 对象类型
* @return {@link Collector}
*/
public static <T> Collector<T, ?, String> joining(CharSequence delimiter) {
return joining(delimiter, Object::toString);
}
/**
* 提供任意对象的Join操作的{@link Collector}实现
*
* @param delimiter 分隔符
* @param toStringFunc 自定义指定对象转换为字符串的方法
* @param <T> 对象类型
* @return {@link Collector}
*/
public static <T> Collector<T, ?, String> joining(CharSequence delimiter,
Function<T, ? extends CharSequence> toStringFunc) {
return joining(delimiter, StrUtil.EMPTY, StrUtil.EMPTY, toStringFunc);
}
/**
* 提供任意对象的Join操作的{@link Collector}实现
*
* @param delimiter 分隔符
* @param prefix 前缀
* @param suffix 后缀
* @param toStringFunc 自定义指定对象转换为字符串的方法
* @param <T> 对象类型
* @return {@link Collector}
*/
public static <T> Collector<T, ?, String> joining(CharSequence delimiter,
CharSequence prefix,
CharSequence suffix,
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()
);
}
}

View File

@ -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 <T> 输入数据类型
* @param <A> 累积结果的容器类型
* @param <R> 数据结果类型
* @since 5.6.7
*/
public class SimpleCollector<T, A, R> implements Collector<T, A, R> {
/**
* 创建新的结果容器容器类型为A
*/
private final Supplier<A> supplier;
/**
* 将输入元素合并到结果容器中
*/
private final BiConsumer<A, T> accumulator;
/**
* 合并两个结果容器并行流使用将多个线程产生的结果容器合并
*/
private final BinaryOperator<A> combiner;
/**
* 将结果容器转换成最终的表示
*/
private final Function<A, R> finisher;
/**
* 特征值枚举{@link Characteristics}
* <ul>
* <li>CONCURRENT 表示结果容器只有一个即使是在并行流的情况下
* 只有在并行流且收集器不具备此特性的情况下combiner()返回的lambda表达式才会执行中间结果容器只有一个就无需合并
* 设置此特性时意味着多个线程可以对同一个结果容器调用因此结果容器必须是线程安全的</li>
* <li>UNORDERED 表示流中的元素无序</li>
* <li>IDENTITY_FINISH表示中间结果容器类型与最终结果类型一致设置此特性时finiser()方法不会被调用</li>
* </ul>
*/
private final Set<Characteristics> characteristics;
/**
* 构造
*
* @param supplier 创建新的结果容器函数
* @param accumulator 将输入元素合并到结果容器中函数
* @param combiner 合并两个结果容器函数并行流使用将多个线程产生的结果容器合并
* @param finisher 将结果容器转换成最终的表示函数
* @param characteristics 特征值枚举
*/
public SimpleCollector(Supplier<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Function<A, R> finisher,
Set<Characteristics> 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<A> supplier,
BiConsumer<A, T> accumulator,
BinaryOperator<A> combiner,
Set<Characteristics> characteristics) {
this(supplier, accumulator, combiner, i -> (R) i, characteristics);
}
@Override
public BiConsumer<A, T> accumulator() {
return accumulator;
}
@Override
public Supplier<A> supplier() {
return supplier;
}
@Override
public BinaryOperator<A> combiner() {
return combiner;
}
@Override
public Function<A, R> finisher() {
return finisher;
}
@Override
public Set<Characteristics> characteristics() {
return characteristics;
}
}

View File

@ -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 <T> Stream<T> of(T... values) {
if (null == values) {
return null;
}
return Stream.of(values);
}
/**
* {@link Iterable}转换为{@link Stream}默认非并行
*
* @param iterable 集合
* @param <T> 集合元素类型
* @return {@link Stream}
*/
public static <T> Stream<T> of(Iterable<T> iterable) {
return of(iterable, false);
}
/**
* {@link Iterable}转换为{@link Stream}
*
* @param iterable 集合
* @param parallel 是否并行
* @param <T> 集合元素类型
* @return {@link Stream}
*/
public static <T> Stream<T> of(Iterable<T> 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 <T> 创建元素类型
* @return {@link Stream}
*/
public static <T> Stream<T> of(T seed, UnaryOperator<T> elementCreator, int limit) {
return Stream.iterate(seed, elementCreator).limit(limit);
}
/**
* 将Stream中所有元素以指定分隔符合并为一个字符串对象默认调用toString方法
*
* @param stream {@link Stream}
* @param delimiter 分隔符
* @param <T> 元素类型
* @return 字符串
*/
public static <T> String join(Stream<T> stream, CharSequence delimiter) {
return stream.collect(CollectorUtil.joining(delimiter));
}
/**
* 将Stream中所有元素以指定分隔符合并为一个字符串
*
* @param stream {@link Stream}
* @param delimiter 分隔符
* @param toStringFunc 元素转换为字符串的函数
* @param <T> 元素类型
* @return 字符串
*/
public static <T> String join(Stream<T> stream, CharSequence delimiter,
Function<T, ? extends CharSequence> toStringFunc) {
return stream.collect(CollectorUtil.joining(delimiter, toStringFunc));
}
}

View File

@ -0,0 +1,7 @@
/**
* Java8的stream相关封装
*
* @author looly
*
*/
package cn.hutool.core.stream;

View File

@ -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<Integer> stream = StreamUtil.of(2, x -> x * 2, 4);
final String result = stream.collect(CollectorUtil.joining(","));
Assert.assertEquals("2,4,8,16", result);
}
}