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 e3659496c..af022870d 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,12 +1,25 @@ package cn.hutool.core.stream; +import cn.hutool.core.collection.CollUtil; import cn.hutool.core.lang.Opt; +import cn.hutool.core.math.NumberUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjUtil; - +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.List; import java.util.Objects; +import java.util.OptionalDouble; import java.util.Spliterator; -import java.util.function.*; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.function.ToDoubleFunction; +import java.util.function.ToIntFunction; +import java.util.function.ToLongFunction; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -97,7 +110,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream 元素类型 * @return 包含单个元素的串行流 */ @@ -109,9 +122,9 @@ public class EasyStream extends AbstractEnhancedWrappedStream 元素类型 + * @param 元素类型 * @return 包含指定元素的串行流 - * 从一个安全数组中创建流 + * 从一个安全数组中创建流 */ @SafeVarargs @SuppressWarnings("varargs") @@ -123,7 +136,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream 元素类型 + * @param 元素类型 * @return 流 */ public static EasyStream of(final Iterable iterable) { @@ -135,7 +148,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream 元素类型 + * @param 元素类型 * @return 流 */ public static EasyStream of(final Iterable iterable, final boolean parallel) { @@ -150,7 +163,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream 元素类型 + * @param 元素类型 * @return 流 */ public static EasyStream of(final Stream stream) { @@ -166,9 +179,9 @@ public class EasyStream extends AbstractEnhancedWrappedStream * - * @param 元素类型 + * @param 元素类型 * @param seed 初始值 - * @param f 用上一个元素作为参数执行并返回一个新的元素 + * @param f 用上一个元素作为参数执行并返回一个新的元素 * @return 无限有序流 */ public static EasyStream iterate(final T seed, final UnaryOperator f) { @@ -184,13 +197,14 @@ public class EasyStream extends AbstractEnhancedWrappedStream * - * @param 元素类型 - * @param seed 初始值 + * @param 元素类型 + * @param seed 初始值 * @param hasNext 条件值 - * @param next 用上一个元素作为参数执行并返回一个新的元素 + * @param next 用上一个元素作为参数执行并返回一个新的元素 * @return 无限有序流 */ - public static EasyStream iterate(final T seed, final Predicate hasNext, final UnaryOperator next) { + public static EasyStream iterate(final T seed, final Predicate hasNext, + final UnaryOperator next) { Objects.requireNonNull(next); Objects.requireNonNull(hasNext); return new EasyStream<>(StreamUtil.iterate(seed, hasNext, next)); @@ -198,11 +212,11 @@ public class EasyStream extends AbstractEnhancedWrappedStream 元素类型 - * @param s 用来生成元素的 {@code Supplier} + * @param s 用来生成元素的 {@link Supplier} * @return 无限串行无序流 */ public static EasyStream generate(final Supplier s) { @@ -217,8 +231,8 @@ public class EasyStream extends AbstractEnhancedWrappedStream从重复串行流进行拼接时可能会导致深度调用链甚至抛出 {@code StackOverflowException}

* * @param 元素类型 - * @param a 第一个流 - * @param b 第二个流 + * @param a 第一个流 + * @param b 第二个流 * @return 拼接两个流之后的流 */ public static EasyStream concat(final Stream a, final Stream b) { @@ -228,12 +242,13 @@ public class EasyStream extends AbstractEnhancedWrappedStream split(final CharSequence str, final String regex) { - return Opt.ofBlankAble(str).map(CharSequence::toString).map(s -> s.split(regex)).map(EasyStream::of).orElseGet(EasyStream::empty); + return Opt.ofBlankAble(str).map(CharSequence::toString).map(s -> s.split(regex)).map(EasyStream::of) + .orElseGet(EasyStream::empty); } // --------------------------------------------------------------- Static method end @@ -244,7 +259,7 @@ public class EasyStream extends AbstractEnhancedWrappedStream 函数执行后返回的类型 + * @param 函数执行后返回的类型 * @return 返回叠加操作后的流 */ @Override @@ -264,6 +279,125 @@ public class EasyStream extends AbstractEnhancedWrappedStream(stream); } + + /** + * 计算int类型的总和 + * + * @param mapper 将对象转换为int的 {@link Function} + * @return int 总和 + */ + public int sum(final ToIntFunction mapper) { + return stream.mapToInt(mapper).sum(); + } + + /** + * 计算long类型的总和 + * + * @param mapper 将对象转换为long的 {@link Function} + * @return long 总和 + */ + public long sum(final ToLongFunction mapper) { + return stream.mapToLong(mapper).sum(); + } + + + /** + * 计算double类型的总和 + * + * @param mapper 将对象转换为double的 {@link Function} + * @return double 总和 + */ + public double sum(final ToDoubleFunction mapper) { + return stream.mapToDouble(mapper).sum(); + } + + + /** + * 计算 {@link Number} 类型的总和 + * + * @param 数字 + * @param mapper 将对象转换为{@link Number} 的 {@link Function} + * @return {@link BigDecimal} , 如果流为空, 返回 {@link BigDecimal#ZERO} + */ + public BigDecimal sum(final Function mapper) { + return stream.map(mapper).reduce(BigDecimal.ZERO, NumberUtil::add, NumberUtil::add); + } + + + /** + * 计算 {@link BigDecimal} 类型的平均值 并以四舍五入的方式保留2位精度 + * + * @param mapper 将对象转换为{@link BigDecimal}的 {@link Function} + * @return 计算后的平均值 如果流的长度为0, 返回 {@link Opt#empty()} + */ + public Opt avg(final Function mapper) { + return avg(mapper, 2); + } + + + /** + * {@link BigDecimal} 类型的平均值 并以四舍五入的方式保留小数点后scale位 + * + * @param mapper 将对象转换为{@link BigDecimal} 的 {@link Function} + * @param scale 保留精度 + * @return 计算后的平均值 如果流的长度为0, 返回 {@link Opt#empty()} + */ + public Opt avg(final Function mapper, final int scale) { + return avg(mapper, scale, RoundingMode.HALF_UP); + } + + /** + * 计算 {@link BigDecimal} 类型的平均值 + * + * @param mapper 将对象转换为{@link BigDecimal} 的 {@link Function} + * @param scale 保留精度 + * @param roundingMode 舍入模式 + * @return 计算后的平均值 如果元素的长度为0 那么会返回 {@link Opt#empty()} + */ + public Opt avg(final Function mapper, final int scale, + final RoundingMode roundingMode) { + //元素列表 + List bigDecimalList = stream.map(mapper).collect(Collectors.toList()); + if (CollUtil.isEmpty(bigDecimalList)) { + return Opt.empty(); + } + return Opt.ofNullable(EasyStream.of(bigDecimalList).reduce(BigDecimal.ZERO, BigDecimal::add) + .divide(NumberUtil.toBigDecimal(bigDecimalList.size()), scale, roundingMode)); + } + + + /** + * 计算int类型的平均值 + * + * @param mapper 将对象转换为int 的 {@link Function} + * @return {@link OptionalDouble} 如果流的长度为0 那么会返回{@link OptionalDouble#empty()} + */ + public OptionalDouble avg(final ToIntFunction mapper) { + return stream.mapToInt(mapper).average(); + } + + /** + * 计算double类型的平均值 + * + * @param mapper 将对象转换为double 的 {@link Function} + * @return {@link OptionalDouble} 如果流的长度为0 那么会返回{@link OptionalDouble#empty()} + */ + public OptionalDouble avg(final ToDoubleFunction mapper) { + return stream.mapToDouble(mapper).average(); + } + + + /** + * 计算double平均值 + * + * @param mapper 将对象转换为long 的 {@link Function} + * @return {@link OptionalDouble} 如果流的长度为0 那么会返回{@link OptionalDouble#empty()} + */ + public OptionalDouble avg(final ToLongFunction mapper) { + return stream.mapToLong(mapper).average(); + } + + /** * 建造者 * @@ -277,12 +411,12 @@ public class EasyStream extends AbstractEnhancedWrappedStream{@code - * accept(t) - * return this; - * } + *
{@code
+		 * 										    accept(t)
+		 * 										    return this;
+		 *                                    }
*/ default Builder add(final T t) { accept(t); 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 0f50b8337..2fa800d3a 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 @@ -1,16 +1,31 @@ package cn.hutool.core.stream; -import cn.hutool.core.collection.ListUtil; -import cn.hutool.core.map.MapUtil; -import org.junit.Assert; -import org.junit.Test; +import static java.util.Collections.singletonList; -import java.util.*; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.lang.Opt; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.math.NumberUtil; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.OptionalDouble; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static java.util.Collections.singletonList; +import org.junit.Assert; +import org.junit.Test; /** * @author VampireAchao @@ -181,7 +196,8 @@ public class EasyStreamTest { Assert.assertEquals(ListUtil.sort(collect2), ListUtil.sort(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() ); } @@ -433,4 +449,110 @@ public class EasyStreamTest { Assert.assertTrue(EasyStream.of(1).isNotEmpty()); } + + @Test + public void testIntSumAndAvg() { + //测试int类型的总和 + int sum = EasyStream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).sum(Integer::intValue); + Assert.assertEquals(55, sum); + + //测试为空 + List integerList = new ArrayList<>(); + int emptySum = EasyStream.of(integerList).sum(Integer::intValue); + Assert.assertEquals(0, emptySum); + + //测试平均值 + OptionalDouble avg = EasyStream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).avg(Integer::intValue); + Assert.assertTrue(avg.isPresent()); + Assert.assertEquals(5.5, avg.getAsDouble(), 2); + + //测试元素为空 + OptionalDouble emptyAvg = EasyStream.of(integerList).avg(Integer::intValue); + Assert.assertFalse(emptyAvg.isPresent()); + + } + + @Test + public void testDoubleSumAndAvg() { + //测试double类型的sum + double doubleSum = EasyStream.of(1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10).sum(Double::doubleValue); + Assert.assertEquals(59.6, doubleSum, 2); + + //测试double类型的sum 无元素double + List doubleList = new ArrayList<>(); + double emptySum = EasyStream.of(doubleList).sum(Double::doubleValue); + Assert.assertEquals(0.0, emptySum, 2); + + //测试double类型的avg + OptionalDouble doubleAvg = EasyStream.of(1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10) + .avg(Double::doubleValue); + Assert.assertTrue(doubleAvg.isPresent()); + Assert.assertEquals(5.96, doubleAvg.getAsDouble(), 2); + + //测试double类型的 空元素的avg + OptionalDouble emptyDoubleAvg = EasyStream.of(doubleList).avg(Double::doubleValue); + Assert.assertFalse(emptyDoubleAvg.isPresent()); + + } + + @Test + public void testLongSumAndAvg() { + //测试long类型的sum + long sum = EasyStream.of(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L).sum(Long::longValue); + Assert.assertEquals(55L, sum); + + //测试long类型的空元素 sum + List longList = new ArrayList<>(); + long emptySum = EasyStream.of(longList).sum(Long::longValue); + Assert.assertEquals(0L, emptySum); + + //测试long类型的avg + OptionalDouble doubleAvg = EasyStream.of(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L).avg(Long::longValue); + Assert.assertTrue(doubleAvg.isPresent()); + Assert.assertEquals(5.5, doubleAvg.getAsDouble(), 2); + + //测试long类型的avg 空元素 + OptionalDouble emptyDoubleAvg = EasyStream.of(longList).avg(Long::longValue); + Assert.assertFalse(emptyDoubleAvg.isPresent()); + + + } + + @Test + public void testBigDecimalSumAndAvg() { + //测试bigDecimal的sum + BigDecimal sum = EasyStream.of(1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10).map(NumberUtil::toBigDecimal) + .sum(Function.identity()); + Assert.assertEquals(NumberUtil.toBigDecimal(59.6), sum); + + //测试bigDecimal的sum 空元素 + List bigDecimalEmptyList = new ArrayList<>(); + BigDecimal emptySum = EasyStream.of(bigDecimalEmptyList).sum(Function.identity()); + Assert.assertEquals(BigDecimal.ZERO, emptySum); + + //测试bigDecimal的avg全参 + Opt bigDecimalAvgFullParam = EasyStream.of(1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10) + .map(NumberUtil::toBigDecimal) + .avg(Function.identity(), 2, RoundingMode.HALF_UP); + Assert.assertEquals(NumberUtil.toBigDecimal(5.96), bigDecimalAvgFullParam.get()); + + //测试bigDecimal的avg单参 + Opt bigDecimalAvgOneParam = EasyStream.of(1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10) + .map(NumberUtil::toBigDecimal) + .avg(Function.identity()); + Assert.assertEquals(NumberUtil.toBigDecimal(5.96), bigDecimalAvgOneParam.get()); + + //测试bigDecimal的avg双参 + Opt bigDecimalAvgTwoParam = EasyStream.of(1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10) + .map(NumberUtil::toBigDecimal) + .avg(Function.identity(), 2); + Assert.assertEquals(NumberUtil.toBigDecimal(5.96), bigDecimalAvgTwoParam.get()); + + //测试bigDecimal的avg 空元素 + Opt emptyBigDecimalAvg = EasyStream.of(bigDecimalEmptyList) + .avg(Function.identity(), 2, RoundingMode.HALF_UP); + Assert.assertFalse(emptyBigDecimalAvg.isPresent()); + + + } }