├── src ├── main │ └── java │ │ └── com │ │ └── taowater │ │ └── ztream │ │ ├── assist │ │ ├── BreakException.java │ │ ├── Box.java │ │ ├── Functions.java │ │ ├── Spliterators.java │ │ └── ExCollectors.java │ │ ├── op │ │ ├── math │ │ │ ├── Peak.java │ │ │ └── Math.java │ │ ├── Distinct.java │ │ ├── filter │ │ │ ├── Wrapper.java │ │ │ ├── Filter.java │ │ │ ├── CompareX.java │ │ │ ├── Compare.java │ │ │ └── ConditionCompare.java │ │ ├── Join.java │ │ ├── ToMap.java │ │ ├── sort │ │ │ ├── Desc.java │ │ │ ├── Asc.java │ │ │ ├── Sort.java │ │ │ └── Sorter.java │ │ ├── ToEntry.java │ │ ├── judge │ │ │ └── Judge.java │ │ ├── Collect.java │ │ └── GroupBy.java │ │ ├── AbstractZtream.java │ │ ├── EntryZtream.java │ │ ├── IZtream.java │ │ ├── Any.java │ │ └── Ztream.java └── test │ └── java │ └── com │ └── taowater │ └── ztream │ ├── TestUtil.java │ ├── TestClass.java │ └── ZtreamTest.java ├── .gitignore ├── LICENSE ├── README.md └── pom.xml /src/main/java/com/taowater/ztream/assist/BreakException.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.assist; 2 | 3 | /** 4 | * 用于跳出forEach 5 | * 6 | * @author zhu56 7 | */ 8 | public class BreakException extends RuntimeException { 9 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #target 2 | target/ 3 | #.idea 4 | .idea/ 5 | # Compiled class file 6 | *.class 7 | .*/ 8 | 9 | # Log file 10 | *.log 11 | 12 | # BlueJ files 13 | *.ctxt 14 | 15 | # Mobile Tools for Java (J2ME) 16 | .mtj.tmp/ 17 | 18 | # Package Files # 19 | *.jar 20 | *.war 21 | *.nar 22 | *.ear 23 | *.zip 24 | *.tar.gz 25 | *.rar 26 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/math/Peak.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op.math; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * 记录最值的实体 9 | * 10 | * @author zhu56 11 | */ 12 | @Data 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | public class Peak { 16 | 17 | private T max; 18 | 19 | private T min; 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/taowater/ztream/TestUtil.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream; 2 | 3 | import lombok.experimental.UtilityClass; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | @UtilityClass 9 | public class TestUtil { 10 | public static List initList(T... values) { 11 | if (values == null || values.length == 0) { 12 | return new ArrayList<>(); 13 | } 14 | List list = new ArrayList<>(); 15 | for (T value : values) { 16 | list.add(value); 17 | } 18 | return list; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Zhu56 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/Distinct.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op; 2 | 3 | import com.taowater.ztream.Any; 4 | import com.taowater.ztream.IZtream; 5 | import com.taowater.ztream.assist.Box; 6 | 7 | import java.util.function.Function; 8 | 9 | /** 10 | * 去重相关操作 11 | * 12 | * @author zhu56 13 | */ 14 | public interface Distinct> extends IZtream { 15 | 16 | /** 17 | * 按某属性去重 18 | * 19 | * @param fun 属性 20 | */ 21 | default S distinct(Function fun) { 22 | return distinct(true, fun); 23 | } 24 | 25 | /** 26 | * 按某属性去重 27 | * 28 | * @param condition 执行条件 29 | * @param fun 属性 30 | */ 31 | default S distinct(boolean condition, Function fun) { 32 | if (!condition) { 33 | return ztream(this); 34 | } 35 | return ztream(map(t -> new Box.PairBox<>(t, Any.of(t).get(fun))) 36 | .distinct() 37 | .map(Box::getA)); 38 | } 39 | 40 | /** 41 | * 去重 42 | * 43 | * @param condition 执行条件 44 | */ 45 | default S distinct(boolean condition) { 46 | if (!condition) { 47 | return ztream(this); 48 | } 49 | return distinct(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/assist/Box.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.assist; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | import java.util.Objects; 7 | import java.util.function.Consumer; 8 | 9 | 10 | /** 11 | * 包装类 12 | * 13 | * @author zhu56 14 | */ 15 | @Setter 16 | @Getter 17 | @SuppressWarnings("unused") 18 | public class Box implements Consumer { 19 | private A a; 20 | 21 | Box() { 22 | } 23 | 24 | public Box(A obj) { 25 | this.a = obj; 26 | } 27 | 28 | @Override 29 | public void accept(A a) { 30 | this.a = a; 31 | } 32 | 33 | @Getter 34 | public static class PairBox extends Box { 35 | private B b; 36 | 37 | public PairBox(A a, B b) { 38 | super(a); 39 | this.b = b; 40 | } 41 | 42 | public static PairBox single(T a) { 43 | return new PairBox<>(a, a); 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | return Objects.hashCode(b); 49 | } 50 | 51 | @Override 52 | public boolean equals(Object obj) { 53 | return obj != null && obj.getClass() == PairBox.class && Objects.equals(b, ((PairBox) obj).b); 54 | } 55 | } 56 | } 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/filter/Wrapper.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op.filter; 2 | 3 | 4 | import lombok.Getter; 5 | 6 | import java.util.function.Consumer; 7 | import java.util.function.Predicate; 8 | 9 | /** 10 | * 条件 11 | * 12 | * @author zhu56 13 | */ 14 | @Getter 15 | @SuppressWarnings("unused") 16 | public class Wrapper implements Compare> { 17 | 18 | private Predicate condition = o -> true; 19 | 20 | @Override 21 | public Wrapper filter(Predicate predicate) { 22 | this.condition = condition.and(predicate); 23 | return this; 24 | } 25 | 26 | /** 27 | * 且 28 | */ 29 | public Wrapper and(Consumer> consumer) { 30 | Wrapper wrapper = new Wrapper<>(); 31 | consumer.accept(wrapper); 32 | this.condition = condition.and(wrapper.condition); 33 | return this; 34 | } 35 | 36 | /** 37 | * 或 38 | */ 39 | @SuppressWarnings("UnusedReturnValue") 40 | public Wrapper or(Consumer> consumer) { 41 | Wrapper wrapper = new Wrapper<>(); 42 | consumer.accept(wrapper); 43 | this.condition = condition.or(wrapper.condition); 44 | return this; 45 | } 46 | 47 | @Override 48 | public Wrapper filter(boolean condition, Predicate predicate) { 49 | if (condition) { 50 | return this.filter(predicate); 51 | } 52 | return this; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/com/taowater/ztream/TestClass.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream; 2 | 3 | import lombok.*; 4 | import lombok.experimental.UtilityClass; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | 10 | @UtilityClass 11 | public class TestClass { 12 | 13 | @Data 14 | @EqualsAndHashCode(callSuper = true) 15 | @Builder 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public static class Student extends Person { 19 | private String name; 20 | private Integer age; 21 | } 22 | 23 | @Data 24 | public static class Person { 25 | private String sex; 26 | private Boolean flag; 27 | private boolean flag2; 28 | private int flag3; 29 | } 30 | 31 | @EqualsAndHashCode(callSuper = true) 32 | @Data 33 | public static class Teacher extends Person { 34 | private String name; 35 | private Long money; 36 | } 37 | 38 | 39 | public static List testList = new ArrayList<>(); 40 | 41 | static { 42 | testList.add(Student.builder().name("小猪").age(1).build()); 43 | testList.add(Student.builder().name("小狗").age(2).build()); 44 | testList.add(null); 45 | testList.add(Student.builder().name(null).age(3).build()); 46 | testList.add(Student.builder().name(" ").age(9).build()); 47 | testList.add(Student.builder().name("小狗").age(null).build()); 48 | testList.add(Student.builder().name(null).age(4).build()); 49 | testList.add(Student.builder().name("").age(89).build()); 50 | testList.add(Student.builder().name("小猪").age(50).build()); 51 | testList.add(Student.builder().name("小猪").age(7).build()); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/filter/Filter.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op.filter; 2 | 3 | import com.taowater.ztream.IZtream; 4 | import com.taowater.ztream.assist.Functions; 5 | 6 | import java.util.function.Consumer; 7 | import java.util.function.Function; 8 | import java.util.function.Predicate; 9 | 10 | /** 11 | * 过滤操作 12 | * 13 | * @author zhu56 14 | * @see 0.0.3 15 | */ 16 | @SuppressWarnings("unused") 17 | public interface Filter> extends IZtream, Compare { 18 | 19 | @Override 20 | default S filter(Predicate predicate) { 21 | return IZtream.super.filter(predicate); 22 | } 23 | 24 | @Override 25 | default S filter(boolean condition, Predicate predicate) { 26 | if (condition) { 27 | return filter(predicate); 28 | } 29 | return ztream(this); 30 | } 31 | 32 | /** 33 | * 条件过滤 34 | * 35 | * @param consumer 消费者 36 | * @return {@link S } 37 | */ 38 | default S query(Consumer> consumer) { 39 | Wrapper wrapper = new Wrapper<>(); 40 | consumer.accept(wrapper); 41 | return ztream(filter(e -> e, wrapper.getCondition())); 42 | } 43 | 44 | /** 45 | * 过滤条件为假 46 | * 47 | * @param predicate 谓语 48 | * @return {@link S } 49 | */ 50 | default S isFalse(Function predicate) { 51 | return filter(Functions.of(predicate).negate()); 52 | } 53 | 54 | /** 55 | * 过滤条件为真 56 | * 57 | * @param predicate 谓语 58 | * @return {@link S } 59 | */ 60 | default S isTrue(Function predicate) { 61 | return filter(Functions.of(predicate)); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/Join.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op; 2 | 3 | 4 | import com.taowater.ztream.Any; 5 | import com.taowater.ztream.assist.ExCollectors; 6 | 7 | import java.util.Objects; 8 | import java.util.function.Function; 9 | import java.util.stream.Stream; 10 | 11 | /** 12 | * join操作 13 | * 14 | * @author Zhu56 15 | * @since 0.0.1 16 | */ 17 | @SuppressWarnings("unused") 18 | public interface Join extends Stream { 19 | 20 | /** 21 | * 返回拼接后的字符串 22 | * 23 | * @return 拼接后的字符串 24 | */ 25 | default String join() { 26 | return join(","); 27 | } 28 | 29 | /** 30 | * 返回拼接后的字符串 31 | * 32 | * @param delimiter 分隔符 33 | * @return 拼接后的字符串 34 | */ 35 | default String join(CharSequence delimiter) { 36 | return join(delimiter, "", ""); 37 | } 38 | 39 | /** 40 | * 拼接属性 41 | * 42 | * @param fun 函数 43 | * @return 拼接后的字符串 44 | */ 45 | default String join(Function fun) { 46 | return join(fun, ","); 47 | } 48 | 49 | /** 50 | * 拼接属性,指定分隔符 51 | * 52 | * @param fun 函数 53 | * @param delimiter 分隔符 54 | * @return 拼接后的字符串 55 | */ 56 | default String join(Function fun, CharSequence delimiter) { 57 | return map(e -> Any.of(e).get(fun)).collect(ExCollectors.join(delimiter)); 58 | } 59 | 60 | /** 61 | * 返回拼接后的字符串 62 | * 63 | * @param delimiter 分隔符 64 | * @param prefix 前缀 65 | * @param suffix 后缀 66 | * @return 拼接后的字符串 67 | */ 68 | default String join(CharSequence delimiter, 69 | CharSequence prefix, 70 | CharSequence suffix) { 71 | if (Objects.isNull(delimiter)) { 72 | delimiter = ","; 73 | } 74 | return collect(ExCollectors.join(delimiter, prefix, suffix)); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/AbstractZtream.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream; 2 | 3 | 4 | import com.taowater.ztream.op.Collect; 5 | import com.taowater.ztream.op.Join; 6 | import com.taowater.ztream.op.ToEntry; 7 | import com.taowater.ztream.op.filter.Filter; 8 | import com.taowater.ztream.op.judge.Judge; 9 | import com.taowater.ztream.op.math.Math; 10 | import com.taowater.ztream.op.sort.Sort; 11 | 12 | import java.util.stream.Stream; 13 | 14 | /** 15 | * 抽象增强流 16 | * 17 | * @author Zhu56 18 | */ 19 | @SuppressWarnings("unused") 20 | public abstract class AbstractZtream> implements Filter, Sort, Collect, 21 | Math, 22 | Join, 23 | ToEntry, 24 | Judge { 25 | protected final Stream stream; 26 | 27 | protected AbstractZtream(Stream stream) { 28 | this.stream = stream; 29 | } 30 | 31 | @Override 32 | public Stream stream() { 33 | return stream; 34 | } 35 | 36 | /** 37 | * 第一个 38 | * 39 | * @return {@link Any}<{@link T}> 40 | */ 41 | public Any first() { 42 | return Any.of(findFirst(false).orElse(null)); 43 | } 44 | 45 | /** 46 | * 获取第一个元素 47 | * 48 | * @return {@link T } 49 | */ 50 | public T getFirst() { 51 | return first().orElse(null); 52 | } 53 | 54 | /** 55 | * 任意一个 56 | * 57 | * @return {@link Any}<{@link T}> 58 | */ 59 | public Any any() { 60 | return Any.of(findAny(false).orElse(null)); 61 | } 62 | 63 | /** 64 | * 最后一个 65 | * 66 | * @return {@link Any }<{@link T }> 67 | */ 68 | public Any last() { 69 | return Any.of(stream.reduce((a, b) -> b).orElse(null)); 70 | } 71 | 72 | /** 73 | * 获取最后一个 74 | * 75 | * @return {@link T } 76 | */ 77 | public T getLast() { 78 | return last().orElse(null); 79 | } 80 | 81 | /** 82 | * 随机取一个 83 | * 84 | * @return {@link Any}<{@link T}> 85 | */ 86 | public Any random() { 87 | return shuffle().first(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/ToMap.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.Objects; 6 | import java.util.function.Function; 7 | import java.util.function.Supplier; 8 | import java.util.stream.Stream; 9 | 10 | /** 11 | * 映射操作 12 | * 13 | * @author Zhu56 14 | * @since 0.0.1 15 | */ 16 | public interface ToMap extends Stream { 17 | 18 | 19 | /** 20 | * 映射 21 | * 22 | * @param funK 键方法 23 | * @return 映射结果 24 | */ 25 | default Map toMap(Function funK) { 26 | return this.toMap(funK, Function.identity()); 27 | } 28 | 29 | /** 30 | * 映射 31 | * 32 | * @param funK 键方法 33 | * @param mapFactory map工厂 34 | * @return 映射结果 35 | */ 36 | default > M toMap( 37 | Function funK, 38 | Supplier mapFactory) { 39 | return this.toMap(funK, Function.identity(), mapFactory); 40 | } 41 | 42 | /** 43 | * 映射 44 | * 45 | * @param funK 键方法 46 | * @param funV 值方法 47 | * @return 映射结果 48 | */ 49 | default Map toMap( 50 | Function funK, 51 | Function funV) { 52 | return this.toMap(funK, funV, HashMap::new); 53 | } 54 | 55 | /** 56 | * 映射 57 | * 58 | * @param funK 键方法 59 | * @param funV 值方法 60 | * @param mapFactory map工厂 61 | * @return 映射结果 62 | */ 63 | default > M toMap( 64 | Function funK, 65 | Function funV, 66 | Supplier mapFactory) { 67 | return this.collect(mapFactory, (map, item) -> { 68 | K key = null; 69 | V value = null; 70 | if (Objects.nonNull(item)) { 71 | key = funK.apply(item); 72 | value = funV.apply(item); 73 | } 74 | if (!map.containsKey(key)) { 75 | map.put(key, value); 76 | } 77 | }, 78 | Map::putAll); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/sort/Desc.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op.sort; 2 | 3 | import java.util.Comparator; 4 | import java.util.function.Function; 5 | 6 | /** 7 | * 降序排序方法 8 | * 9 | * @author zhu56 10 | */ 11 | @SuppressWarnings("unused") 12 | public interface Desc { 13 | 14 | 15 | /** 16 | * 倒序 17 | * 18 | * @param condition 装载条件 19 | * @param keyExtractor 属性 20 | * @param nullFirst 是否null值前置 21 | */ 22 | > S desc(boolean condition, Function keyExtractor, boolean nullFirst); 23 | 24 | 25 | /** 26 | * 倒序 27 | * 28 | * @param keyExtractor 属性 29 | * @param nullFirst 是否null值前置 30 | */ 31 | default > S desc(Function keyExtractor, boolean nullFirst) { 32 | return desc(true, keyExtractor, nullFirst); 33 | } 34 | 35 | /** 36 | * 倒序 37 | * 38 | * @param condition 装载条件 39 | * @param keyExtractor 属性 40 | */ 41 | default > S desc(boolean condition, Function keyExtractor) { 42 | return desc(condition, keyExtractor, true); 43 | } 44 | 45 | /** 46 | * 倒序 47 | * 48 | * @param keyExtractor 属性 49 | */ 50 | default > S desc(Function keyExtractor) { 51 | return desc(true, keyExtractor); 52 | } 53 | 54 | /** 55 | * 指定逻辑倒序 56 | * 57 | * @param condition 装载条件 58 | * @param comparator 比较逻辑 59 | * @param nullFirst 是否null值前置 60 | */ 61 | S desc(boolean condition, Comparator comparator, boolean nullFirst); 62 | 63 | /** 64 | * 指定逻辑倒序 65 | * 66 | * @param comparator 比较逻辑 67 | * @param nullFirst 是否null值前置 68 | */ 69 | default S desc(Comparator comparator, boolean nullFirst) { 70 | return desc(true, comparator, nullFirst); 71 | } 72 | 73 | /** 74 | * 指定逻辑倒序 75 | * 76 | * @param condition 装载条件 77 | * @param comparator 比较逻辑 78 | */ 79 | default S desc(boolean condition, Comparator comparator) { 80 | return desc(condition, comparator, true); 81 | } 82 | 83 | /** 84 | * 指定逻辑倒序 85 | * 86 | * @param comparator 比较逻辑 87 | */ 88 | default S desc(Comparator comparator) { 89 | return desc(comparator, true); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/sort/Asc.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op.sort; 2 | 3 | import java.util.Comparator; 4 | import java.util.function.Function; 5 | 6 | /** 7 | * 升序排序方法 8 | * 9 | * @author zhu56 10 | */ 11 | @SuppressWarnings("unused") 12 | public interface Asc { 13 | 14 | 15 | /** 16 | * 升序 17 | * 18 | * @param condition 装载条件 19 | * @param keyExtractor 属性 20 | * @param nullFirst 是否null值前置 21 | */ 22 | > S asc(boolean condition, Function keyExtractor, boolean nullFirst); 23 | 24 | 25 | /** 26 | * 升序 27 | * 28 | * @param keyExtractor 属性 29 | * @param nullFirst 是否null值前置 30 | */ 31 | @SuppressWarnings("UnusedReturnValue") 32 | default > S asc(Function keyExtractor, boolean nullFirst) { 33 | return asc(true, keyExtractor, nullFirst); 34 | } 35 | 36 | /** 37 | * 升序 38 | * 39 | * @param condition 装载条件 40 | * @param keyExtractor 属性 41 | */ 42 | default > S asc(boolean condition, Function keyExtractor) { 43 | return asc(condition, keyExtractor, true); 44 | } 45 | 46 | /** 47 | * 升序 48 | * 49 | * @param keyExtractor 属性 50 | */ 51 | default > S asc(Function keyExtractor) { 52 | return asc(true, keyExtractor); 53 | } 54 | 55 | /** 56 | * 指定逻辑升序 57 | * 58 | * @param condition 装载条件 59 | * @param comparator 比较逻辑 60 | * @param nullFirst 是否null值前置 61 | */ 62 | S asc(boolean condition, Comparator comparator, boolean nullFirst); 63 | 64 | /** 65 | * 指定逻辑升序 66 | * 67 | * @param comparator 比较逻辑 68 | * @param nullFirst 是否null值前置 69 | */ 70 | default S asc(Comparator comparator, boolean nullFirst) { 71 | return asc(true, comparator, nullFirst); 72 | } 73 | 74 | /** 75 | * 指定逻辑升序 76 | * 77 | * @param condition 装载条件 78 | * @param comparator 比较逻辑 79 | */ 80 | default S asc(boolean condition, Comparator comparator) { 81 | return asc(condition, comparator, true); 82 | } 83 | 84 | /** 85 | * 指定逻辑升序 86 | * 87 | * @param comparator 比较逻辑 88 | */ 89 | default S asc(Comparator comparator) { 90 | return asc(comparator, true); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/ToEntry.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op; 2 | 3 | import com.taowater.ztream.EntryZtream; 4 | import com.taowater.ztream.IZtream; 5 | import com.taowater.ztream.assist.Functions; 6 | import com.taowater.ztream.assist.Spliterators; 7 | import lombok.var; 8 | 9 | import java.util.List; 10 | import java.util.function.Function; 11 | import java.util.stream.Collector; 12 | import java.util.stream.Collectors; 13 | import java.util.stream.StreamSupport; 14 | 15 | /** 16 | * 转为二元流的操作 17 | * 18 | * @author zhu56 19 | * @date 2025/06/25 01:11 20 | */ 21 | public interface ToEntry> extends IZtream, Distinct { 22 | 23 | 24 | /** 25 | * 映射 26 | * 27 | * @param funK 键函数 28 | * @return {@link EntryZtream }<{@link K }, {@link T }> 29 | */ 30 | default EntryZtream hash(Function funK) { 31 | return hash(funK, Function.identity()); 32 | } 33 | 34 | /** 35 | * 映射 36 | * 37 | * @param funK 键函数 38 | * @param funV 值函数 39 | * @return {@link EntryZtream }<{@link K }, {@link V }> 40 | */ 41 | default EntryZtream hash(Function funK, Function funV) { 42 | return EntryZtream.of(distinct(funK).map(e -> Functions.entry(e, funK, funV))); 43 | } 44 | 45 | 46 | /** 47 | * 分组 48 | * 49 | * @param funK 键函数 50 | * @param funV 值函数 51 | * @param downstream 组元素处理 52 | * @return {@link EntryZtream }<{@link K }, {@link D }> 53 | */ 54 | default EntryZtream group(Function funK, Function funV, Collector downstream) { 55 | var spliterator = new Spliterators.GroupSpliterator<>(spliterator(), funK, funV, downstream); 56 | return EntryZtream.of(StreamSupport.stream(spliterator, isParallel())); 57 | } 58 | 59 | /** 60 | * 分组 61 | * 62 | * @param funK 键函数 63 | * @param funV 值函数 64 | * @return {@link EntryZtream }<{@link K }, {@link List }<{@link V }>> 65 | */ 66 | default EntryZtream> group(Function funK, Function funV) { 67 | return group(funK, funV, Collectors.toList()); 68 | } 69 | 70 | /** 71 | * 分组 72 | * 73 | * @param funK 键函数 74 | * @return {@link EntryZtream }<{@link K }, {@link List }<{@link T }>> 75 | */ 76 | default EntryZtream> group(Function funK) { 77 | return group(funK, Function.identity()); 78 | } 79 | 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/judge/Judge.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op.judge; 2 | 3 | import com.taowater.ztream.Any; 4 | import com.taowater.ztream.IZtream; 5 | import com.taowater.ztream.assist.Functions; 6 | 7 | import java.util.HashSet; 8 | import java.util.Set; 9 | import java.util.function.BiPredicate; 10 | import java.util.function.Function; 11 | import java.util.function.Predicate; 12 | import java.util.stream.Stream; 13 | 14 | /** 15 | * 判断操作 16 | */ 17 | public interface Judge> extends IZtream { 18 | 19 | /** 20 | * 判断元素是否重复 21 | */ 22 | default boolean hadRepeat() { 23 | Set set = new HashSet<>(); 24 | return anyMatch(x -> !set.add(x)); 25 | } 26 | 27 | /** 28 | * 判断元素某属性是重复 29 | * 30 | * @param fun 属性 31 | */ 32 | default boolean hadRepeat(Function fun) { 33 | Set set = new HashSet<>(); 34 | return anyMatch(x -> !set.add(Any.of(x).get(fun))); 35 | } 36 | 37 | /** 38 | * 判断元素指定属性是否任一匹配 39 | * 40 | * @param fun 属性 41 | * @param predicate 条件 42 | */ 43 | default boolean anyMatch(Function fun, Function predicate) { 44 | return judge(Stream::anyMatch, fun, predicate); 45 | } 46 | 47 | /** 48 | * 判断元素指定属性是否全部匹配 49 | * 50 | * @param fun 属性 51 | * @param predicate 条件 52 | * @return boolean 53 | */ 54 | default boolean allMatch(Function fun, Function predicate) { 55 | return judge(Stream::allMatch, fun, predicate); 56 | } 57 | 58 | /** 59 | * 判断元素指定属性是否全都不匹配 60 | * 61 | * @param fun 属性 62 | * @param predicate 条件 63 | * @return 判断结果 64 | */ 65 | default boolean noneMatch(Function fun, Function predicate) { 66 | return judge(Stream::noneMatch, fun, predicate); 67 | } 68 | 69 | /** 70 | * 判断 71 | * 72 | * @param handle 指定一种判断方式 73 | * @param fun 属性 74 | * @param predicate 条件 75 | * @return 判断结果 76 | */ 77 | default boolean judge(BiPredicate> handle, Function fun, Function predicate) { 78 | return handle.test(ztream(this), e -> Functions.of(predicate).test(Any.of(e).get(fun))); 79 | } 80 | 81 | /** 82 | * 是否为空 83 | * 84 | * @return 判断结果 85 | */ 86 | default boolean isEmpty() { 87 | return !isNotEmpty(); 88 | } 89 | 90 | /** 91 | * 是否不为空 92 | * 93 | * @return 判断结果 94 | */ 95 | default boolean isNotEmpty() { 96 | return iterator().hasNext(); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/Collect.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op; 2 | 3 | import com.taowater.taol.core.convert.ConvertUtil; 4 | import com.taowater.ztream.Any; 5 | 6 | import java.util.*; 7 | import java.util.function.Function; 8 | import java.util.function.Supplier; 9 | import java.util.stream.Collectors; 10 | import java.util.stream.Stream; 11 | 12 | /** 13 | * 收集操作 14 | * 15 | * @author Zhu56 16 | * @since 0.0.1 17 | */ 18 | public interface Collect extends Stream { 19 | 20 | /** 21 | * 收集为集合 22 | * 23 | * @param collectionFactory 集合工厂 24 | * @return 集合 25 | */ 26 | default > C collect(Supplier collectionFactory) { 27 | return collect(Collectors.toCollection(collectionFactory)); 28 | } 29 | 30 | /** 31 | * 收集属性 32 | * 33 | * @param fun 属性 34 | * @param collectionFactory 集合工厂 35 | * @return 集合 36 | */ 37 | default > C collect(Function fun, Supplier collectionFactory) { 38 | return this.map(e -> Any.of(e).get(fun)).collect(Collectors.toCollection(collectionFactory)); 39 | } 40 | 41 | /** 42 | * 转换类型收集 43 | * 44 | * @param clazz clazz 45 | * @param collectionFactory 收集工厂 46 | * @return 集合 47 | */ 48 | default > C collect(Class clazz, Supplier collectionFactory) { 49 | return this.map(e -> Any.of(e).get(o -> ConvertUtil.convert(o, clazz))).collect(Collectors.toCollection(collectionFactory)); 50 | } 51 | 52 | /** 53 | * 收集属性 54 | * 55 | * @param fun 属性 56 | * @return 属性 ArrayList 集合 57 | */ 58 | default List collect(Function fun) { 59 | return this.collect(fun, ArrayList::new); 60 | } 61 | 62 | /** 63 | * 转换元素类型并收集 64 | * 65 | * @param clazz clazz 66 | * @return 转换 ArrayList 集合 67 | */ 68 | default List collect(Class clazz) { 69 | return this.collect(clazz, ArrayList::new); 70 | } 71 | 72 | /** 73 | * 收集为{@link ArrayList} 74 | * 75 | * @return ArrayList 集合 76 | */ 77 | default List toList() { 78 | return collect(Collectors.toList()); 79 | } 80 | 81 | /** 82 | * 收集某属性为list 83 | * 84 | * @param fun 函数 85 | * @return 属性 ArrayList 集合 86 | */ 87 | default List toList(Function fun) { 88 | return this.collect(fun, ArrayList::new); 89 | } 90 | 91 | /** 92 | * 转换类型收集为list 93 | * 94 | * @param clazz clazz 95 | * @return 转换 ArrayList 集合 96 | */ 97 | default List toList(Class clazz) { 98 | return this.collect(clazz, ArrayList::new); 99 | } 100 | 101 | /** 102 | * 收集为{@link HashSet} 103 | * 104 | * @return HashSet 集合 105 | */ 106 | default Set toSet() { 107 | return collect(Collectors.toSet()); 108 | } 109 | 110 | /** 111 | * 收集某属性为set 112 | * 113 | * @param fun 函数 114 | * @return 属性 HashSet 集合 115 | */ 116 | default Set toSet(Function fun) { 117 | return this.collect(fun, HashSet::new); 118 | } 119 | 120 | /** 121 | * 转换类型收集set 122 | * 123 | * @param clazz 类型 124 | * @return 转换 HashSet 集合 125 | */ 126 | default Set toSet(Class clazz) { 127 | return this.collect(clazz, HashSet::new); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/sort/Sort.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op.sort; 2 | 3 | import com.taowater.ztream.IZtream; 4 | import com.taowater.ztream.assist.Box; 5 | 6 | import java.util.Comparator; 7 | import java.util.concurrent.ThreadLocalRandom; 8 | import java.util.concurrent.atomic.AtomicInteger; 9 | import java.util.function.Consumer; 10 | import java.util.function.Function; 11 | 12 | /** 13 | * 排序操作 14 | * 15 | * @author zhu56 16 | * @since 0.0.3 17 | */ 18 | @SuppressWarnings("unused") 19 | public interface Sort> extends IZtream, Asc, Desc { 20 | 21 | /** 22 | * 升序 23 | * 24 | * @return 新流 25 | */ 26 | default S asc() { 27 | return asc(true); 28 | } 29 | 30 | /** 31 | * 升序 32 | * 33 | * @param nullFirst 是否null值前置 34 | * @return 新流 35 | */ 36 | @SuppressWarnings("unchecked") 37 | default S asc(boolean nullFirst) { 38 | return sort(r -> r.then((Comparator) Comparator.naturalOrder(), nullFirst)); 39 | } 40 | 41 | /** 42 | * 降序 43 | * 44 | * @return 新流 45 | */ 46 | default S desc() { 47 | return desc(true); 48 | } 49 | 50 | /** 51 | * 降序 52 | * 53 | * @param nullFirst 是否null值前置 54 | * @return 新流 55 | */ 56 | @SuppressWarnings("unchecked") 57 | default S desc(boolean nullFirst) { 58 | return sort(r -> r.then((Comparator) Comparator.reverseOrder(), nullFirst)); 59 | } 60 | 61 | /** 62 | * 排序 63 | * 64 | * @param consumer 排序上下分的消费函数 65 | * @return 新流 66 | */ 67 | default S sort(Consumer> consumer) { 68 | Sorter sorter = new Sorter<>(); 69 | consumer.accept(sorter); 70 | return sorted(sorter.getComparator()); 71 | } 72 | 73 | /** 74 | * 洗牌 75 | * 76 | * @return 新流 77 | */ 78 | default S shuffle() { 79 | return shuffle(true); 80 | } 81 | 82 | /** 83 | * 洗牌 84 | * 85 | * @param condition 执行条件 86 | * @return {@link S } 87 | */ 88 | default S shuffle(boolean condition) { 89 | if (!condition) { 90 | return ztream(this); 91 | } 92 | return ztream(map(e -> new Box.PairBox<>(e, ThreadLocalRandom.current().nextInt())).sorted(Comparator.comparing(Box.PairBox::getB)).map(Box::getA)); 93 | } 94 | 95 | /** 96 | * 反转顺序 97 | * 98 | * @return {@link S } 99 | */ 100 | default S reverse() { 101 | return reverse(true); 102 | } 103 | 104 | /** 105 | * 反转顺序 106 | * 107 | * @param condition 执行条件 108 | */ 109 | default S reverse(boolean condition) { 110 | if (!condition) { 111 | return ztream(this); 112 | } 113 | AtomicInteger index = new AtomicInteger(0); 114 | return ztream(map(e -> new Box.PairBox<>(e, index.getAndAdd(1))).sorted(Comparator.comparing((Function, Integer>) Box.PairBox::getB).reversed()).map(Box::getA)); 115 | } 116 | 117 | @Override 118 | default > S desc(boolean condition, Function keyExtractor, boolean nullFirst) { 119 | return sort(r -> r.desc(condition, keyExtractor, nullFirst)); 120 | } 121 | 122 | @Override 123 | default S desc(boolean condition, Comparator comparator, boolean nullFirst) { 124 | return sort(r -> r.desc(condition, comparator, nullFirst)); 125 | } 126 | 127 | @Override 128 | default > S asc(boolean condition, Function keyExtractor, boolean nullFirst) { 129 | return sort(r -> r.asc(condition, keyExtractor, nullFirst)); 130 | } 131 | 132 | @Override 133 | default S asc(boolean condition, Comparator comparator, boolean nullFirst) { 134 | return sort(r -> r.asc(condition, comparator, nullFirst)); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/assist/Functions.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.assist; 2 | 3 | import com.taowater.ztream.Any; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.experimental.UtilityClass; 6 | 7 | import java.lang.invoke.MethodHandle; 8 | import java.lang.invoke.MethodHandles; 9 | import java.util.AbstractMap.SimpleImmutableEntry; 10 | import java.util.Map; 11 | import java.util.Map.Entry; 12 | import java.util.Objects; 13 | import java.util.concurrent.ConcurrentHashMap; 14 | import java.util.concurrent.atomic.AtomicInteger; 15 | import java.util.function.*; 16 | 17 | /** 18 | * 函数 19 | * 20 | * @author zhu56 21 | */ 22 | @UtilityClass 23 | public class Functions { 24 | 25 | private final static Map, Predicate> CACHE = new ConcurrentHashMap<>(); 26 | 27 | /** 28 | * 索引消费者 29 | * 30 | * @author zhu56 31 | * @version 1.0 32 | */ 33 | @RequiredArgsConstructor 34 | public static class IndexedConsumer implements Consumer { 35 | private final AtomicInteger index = new AtomicInteger(0); 36 | 37 | private final ObjIntConsumer consumer; 38 | 39 | @Override 40 | public void accept(T t) { 41 | consumer.accept(t, index.getAndAdd(1)); 42 | } 43 | } 44 | 45 | /** 46 | * 把一个返回布尔值的方法包装成一个拆箱安全的判断方法 47 | * 48 | * @param fun 方法 49 | */ 50 | public static Predicate of(Function fun) { 51 | return e -> { 52 | Boolean result = fun.apply(e); 53 | if (Objects.isNull(result)) { 54 | return false; 55 | } 56 | return result; 57 | }; 58 | } 59 | 60 | /** 61 | * 索引功能 62 | * 63 | * @author zhu56 64 | * @version 1.0 65 | */ 66 | @RequiredArgsConstructor 67 | public static class IndexedFunction implements Function { 68 | private final AtomicInteger index = new AtomicInteger(0); 69 | 70 | private final BiFunction fun; 71 | 72 | @Override 73 | public R apply(T t) { 74 | return fun.apply(t, index.getAndAdd(1)); 75 | } 76 | } 77 | 78 | 79 | /** 80 | * 将一个判断函数包装为空安全的判断函数 81 | * 注意缓存内存消耗 82 | * 83 | * @param predicate 谓语 84 | */ 85 | @SuppressWarnings("unchecked") 86 | public static Predicate safe(Predicate predicate) { 87 | return (Predicate) CACHE.computeIfAbsent(predicate.getClass(), k -> { 88 | try { 89 | MethodHandle mh = MethodHandles.lookup().unreflect(predicate.getClass() 90 | .getMethod("test", Object.class)) 91 | .bindTo(predicate); 92 | return t -> { 93 | if (t == null) { 94 | return false; 95 | } 96 | try { 97 | Boolean result = (Boolean) mh.invoke(t); 98 | return Any.of(result).orElse(false); 99 | } catch (Throwable e) { 100 | throw new RuntimeException(e); 101 | } 102 | }; 103 | } catch (Exception e) { 104 | return predicate; 105 | } 106 | }); 107 | } 108 | 109 | /** 110 | * 构建一个键值对 111 | * 112 | * @param obj 元素 113 | * @param funK 键函数 114 | * @param funV 值函数 115 | */ 116 | public static Entry entry(T obj, Function funK, Function funV) { 117 | K key = null; 118 | V value = null; 119 | if (Objects.nonNull(obj)) { 120 | key = funK.apply(obj); 121 | value = funV.apply(obj); 122 | } 123 | return new SimpleImmutableEntry<>(key, value); 124 | } 125 | 126 | /** 127 | * 构建一个新的键值对 128 | * 129 | * @param entry entry 130 | * @param funK 键函数 131 | * @param funV 值函数 132 | */ 133 | public static Entry entryKeyValue(Entry entry, Function funK, Function funV) { 134 | Function, K> key = Entry::getKey; 135 | Function, V> value = Entry::getValue; 136 | return entry(entry, key.andThen(funK), value.andThen(funV)); 137 | } 138 | 139 | /** 140 | * 反转键值对 141 | * 142 | * @param entry entry 143 | */ 144 | public static Entry flip(Entry entry) { 145 | return entry(entry, Entry::getValue, Entry::getKey); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/filter/CompareX.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op.filter; 2 | 3 | import com.taowater.taol.core.util.EmptyUtil; 4 | 5 | import java.util.Collection; 6 | import java.util.function.Function; 7 | 8 | /** 9 | * 比较操作 10 | * 11 | * @author zhu56 12 | */ 13 | @SuppressWarnings("unused") 14 | public interface CompareX extends ConditionCompare { 15 | 16 | /** 17 | * 等值操作 18 | * 19 | * @param fun 属性 20 | * @param value 值 21 | */ 22 | default W eqX(Function fun, V value) { 23 | return eq(EmptyUtil.isNotEmpty(value), fun, value); 24 | } 25 | 26 | 27 | /** 28 | * in操作 29 | * 30 | * @param fun 属性 31 | * @param values 值 32 | */ 33 | default W inX(Function fun, Collection values) { 34 | return in(EmptyUtil.isNotEmpty(values), fun, values); 35 | } 36 | 37 | /** 38 | * in操作 39 | * 40 | * @param fun 属性 41 | * @param values 值 42 | */ 43 | @SuppressWarnings("unchecked") 44 | default W inX(Function fun, V... values) { 45 | return in(EmptyUtil.isNotEmpty(values), fun, values); 46 | } 47 | 48 | /** 49 | * 过滤在指定集合中的元素 50 | * 51 | * @param values values 52 | */ 53 | default W inX(Collection values) { 54 | return in(EmptyUtil.isNotEmpty(values), values); 55 | } 56 | 57 | /** 58 | * 过滤在指定集合中的元素 59 | * 60 | * @param c c 61 | */ 62 | @SuppressWarnings("all") 63 | default W inX(T... values) { 64 | return in(EmptyUtil.isNotEmpty(values), values); 65 | } 66 | 67 | /** 68 | * 过滤不在指定集合中的元素 69 | * 70 | * @param value value 71 | */ 72 | default W notInX(Collection value) { 73 | return notIn(EmptyUtil.isNotEmpty(value), value); 74 | } 75 | 76 | /** 77 | * 过滤不在指定集合中的元素 78 | * 79 | * @param values 指定值 80 | */ 81 | @SuppressWarnings("all") 82 | default W notInX(T... values) { 83 | return notIn(EmptyUtil.isNotEmpty(values), values); 84 | } 85 | 86 | /** 87 | * notin操作 88 | * 89 | * @param fun 属性 90 | * @param values 值 91 | */ 92 | default W notInX(Function fun, Collection values) { 93 | return notIn(EmptyUtil.isNotEmpty(values), fun, values); 94 | } 95 | 96 | /** 97 | * notin操作 98 | * 99 | * @param fun 属性 100 | * @param values 值 101 | */ 102 | @SuppressWarnings("unchecked") 103 | default W notInX(Function fun, V... values) { 104 | return notIn(EmptyUtil.isNotEmpty(values), fun, values); 105 | } 106 | 107 | 108 | /** 109 | * 小于 110 | * 111 | * @param fun 属性 112 | * @param value 值 113 | */ 114 | default > W ltX(Function fun, N value) { 115 | return lt(EmptyUtil.isNotEmpty(value), fun, value); 116 | } 117 | 118 | /** 119 | * 小于等于 120 | * 121 | * @param fun 属性 122 | * @param value 值 123 | */ 124 | default > W leX(Function fun, N value) { 125 | return le(EmptyUtil.isNotEmpty(value), fun, value); 126 | } 127 | 128 | /** 129 | * 大于 130 | * 131 | * @param fun 属性 132 | * @param value 值 133 | */ 134 | default > W gtX(Function fun, N value) { 135 | return gt(EmptyUtil.isNotEmpty(value), fun, value); 136 | } 137 | 138 | /** 139 | * 大于等于 140 | * 141 | * @param fun 属性 142 | * @param value 值 143 | */ 144 | default > W geX(Function fun, N value) { 145 | return ge(EmptyUtil.isNotEmpty(value), fun, value); 146 | } 147 | 148 | /** 149 | * 区间 150 | * 151 | * @param fun 属性 152 | * @param leftValue 左值 153 | * @param rightValue 右值 154 | */ 155 | default > W betweenX(Function fun, N leftValue, N rightValue) { 156 | return between(EmptyUtil.isAllNotEmpty(leftValue, rightValue), fun, leftValue, rightValue); 157 | } 158 | 159 | /** 160 | * 过滤指定字符属性以value开头的元素 161 | * 162 | * @param fun 属性 163 | * @param value 值 164 | */ 165 | default W rightLikeX(Function fun, String value) { 166 | return rightLike(EmptyUtil.isNotEmpty(value), fun, value); 167 | } 168 | 169 | default W likeX(Function fun, String value) { 170 | return like(EmptyUtil.isNotEmpty(value), fun, value); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/EntryZtream.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream; 2 | 3 | import com.taowater.ztream.assist.Functions; 4 | import lombok.var; 5 | 6 | import java.util.Collection; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | import java.util.Map.Entry; 10 | import java.util.function.*; 11 | import java.util.stream.Stream; 12 | 13 | /** 14 | * 键值对流 15 | */ 16 | @SuppressWarnings({"unused", "unchecked"}) 17 | public final class EntryZtream extends AbstractZtream, EntryZtream> { 18 | 19 | @SuppressWarnings("unchecked") 20 | EntryZtream(Stream> stream) { 21 | super((Stream>) stream); 22 | } 23 | 24 | public static EntryZtream empty() { 25 | return new EntryZtream<>(Stream.empty()); 26 | } 27 | 28 | public static >> EntryZtream of(C collection) { 29 | return new EntryZtream<>(Ztream.of(collection)); 30 | } 31 | 32 | public static >> EntryZtream of(S stream) { 33 | return new EntryZtream<>(stream); 34 | } 35 | 36 | @Override 37 | public EntryZtream ztream(Stream> stream) { 38 | return new EntryZtream<>(stream); 39 | } 40 | 41 | @Override 42 | public Ztream map(Function, ? extends R> mapper) { 43 | return Ztream.of(stream().map(mapper)); 44 | } 45 | 46 | @Override 47 | public Ztream flatMap(Function, ? extends Stream> mapper) { 48 | return Ztream.of(stream().flatMap(mapper)); 49 | } 50 | 51 | public Ztream keys() { 52 | return map(Entry::getKey); 53 | } 54 | 55 | public Ztream values() { 56 | return map(Entry::getValue); 57 | } 58 | 59 | public Map toMap() { 60 | return toMap(HashMap::new); 61 | } 62 | 63 | public Map toMap(Supplier> supplier) { 64 | var map = supplier.get(); 65 | return reduce(map, 66 | (m, e) -> { 67 | m.put(e.getKey(), e.getValue()); 68 | return m; 69 | }, 70 | (m1, m2) -> { 71 | m1.putAll(m2); 72 | return m1; 73 | }); 74 | } 75 | 76 | public Ztream map(BiFunction mapper) { 77 | return map(entry -> mapper.apply(entry.getKey(), entry.getValue())); 78 | } 79 | 80 | public void forEachKeyValue(BiConsumer consumer) { 81 | forEach(e -> consumer.accept(e.getKey(), e.getValue())); 82 | } 83 | 84 | public void forEachKey(Consumer consumer) { 85 | forEach(e -> consumer.accept(e.getKey())); 86 | } 87 | 88 | public void forEachValue(Consumer consumer) { 89 | forEach(e -> consumer.accept(e.getValue())); 90 | } 91 | 92 | public EntryZtream peekKeyValue(BiConsumer consumer) { 93 | return peek(e -> consumer.accept(e.getKey(), e.getValue())); 94 | } 95 | 96 | public EntryZtream peekKey(Consumer consumer) { 97 | return peek(e -> consumer.accept(e.getKey())); 98 | } 99 | 100 | public EntryZtream peekValue(Consumer consumer) { 101 | return peek(e -> consumer.accept(e.getValue())); 102 | } 103 | 104 | public EntryZtream nonNullKey() { 105 | return filter(e -> e.getKey() != null); 106 | } 107 | 108 | public EntryZtream nonNullValue() { 109 | return filter(e -> e.getValue() != null); 110 | } 111 | 112 | public EntryZtream filter(BiPredicate predicate) { 113 | return filter(e -> predicate.test(e.getKey(), e.getValue())); 114 | } 115 | 116 | public EntryZtream filterKey(Predicate predicate) { 117 | return filter(e -> predicate.test(e.getKey())); 118 | } 119 | 120 | public EntryZtream filterValue(Predicate predicate) { 121 | return filter(e -> predicate.test(e.getValue())); 122 | } 123 | 124 | public boolean anyMatch(BiPredicate predicate) { 125 | return anyMatch(e -> predicate.test(e.getKey(), e.getValue())); 126 | } 127 | 128 | public boolean allMatch(BiPredicate predicate) { 129 | return allMatch(e -> predicate.test(e.getKey(), e.getValue())); 130 | } 131 | 132 | public boolean noneMatch(BiPredicate predicate) { 133 | return noneMatch(e -> predicate.test(e.getKey(), e.getValue())); 134 | } 135 | 136 | public EntryZtream mapKey(Function funK) { 137 | return new EntryZtream<>(map(e -> Functions.entryKeyValue(e, funK, Function.identity()))); 138 | } 139 | 140 | public EntryZtream mapValue(Function funV) { 141 | return new EntryZtream<>(map(e -> Functions.entryKeyValue(e, Function.identity(), funV))); 142 | } 143 | 144 | 145 | public Ztream mapKeyValue(BiFunction fun) { 146 | return map(e -> fun.apply(e.getKey(), e.getValue())); 147 | } 148 | 149 | public EntryZtream flip() { 150 | return new EntryZtream<>(map(Functions::flip)); 151 | } 152 | 153 | public EntryZtream distinctValue() { 154 | return distinct(Entry::getValue); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/sort/Sorter.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op.sort; 2 | 3 | import lombok.NoArgsConstructor; 4 | 5 | import java.util.Comparator; 6 | import java.util.Objects; 7 | import java.util.function.Function; 8 | 9 | /** 10 | * 排序器 11 | * 12 | * @author zhu56 13 | */ 14 | @SuppressWarnings({"unused", "UnusedReturnValue"}) 15 | @NoArgsConstructor 16 | public class Sorter implements Asc>, Desc> { 17 | 18 | /** 19 | * 初始化排序为空 20 | */ 21 | private Comparator comparator = null; 22 | 23 | /** 24 | * 元素为null时是否前置 25 | */ 26 | private boolean nullFirst = true; 27 | 28 | public Sorter(boolean nullFirst) { 29 | this.nullFirst = nullFirst; 30 | } 31 | 32 | public Comparator getComparator() { 33 | return Sorter.nullOrder(nullFirst).apply(comparator); 34 | } 35 | 36 | /** 37 | * 空值排序处理 38 | * 39 | * @param nullFirst 是否null值前置 40 | */ 41 | private static Function, Comparator> nullOrder(boolean nullFirst) { 42 | return nullFirst ? Comparator::nullsFirst : Comparator::nullsLast; 43 | } 44 | 45 | /** 46 | * 排序 47 | * 48 | * @param keyExtractor 属性 49 | * @param desc 是否倒序 50 | * @param nullFirst 是否null值前置 51 | * @param condition 条件 52 | */ 53 | public > Sorter sort(boolean condition, Function keyExtractor, boolean desc, boolean nullFirst) { 54 | if (condition) { 55 | Comparator baseOrder = desc ? Comparator.reverseOrder() : Comparator.naturalOrder(); 56 | Comparator otherComparator = Comparator.comparing(keyExtractor, Sorter.nullOrder(nullFirst).apply(baseOrder)); 57 | return then(otherComparator); 58 | } 59 | return this; 60 | } 61 | 62 | /** 63 | * 自定义排序逻辑排序 64 | * 65 | * @param otherComparator 其他比较器 66 | * @param desc 是否倒序 67 | * @param nullFirst 是否null值前置 68 | * @param condition 条件 69 | */ 70 | public Sorter sort(boolean condition, Comparator otherComparator, boolean desc, boolean nullFirst) { 71 | if (condition) { 72 | Comparator baseOrder = desc ? otherComparator.reversed() : otherComparator; 73 | Comparator realOtherComparator = Sorter.nullOrder(nullFirst).apply(baseOrder); 74 | return then(realOtherComparator); 75 | } 76 | return this; 77 | } 78 | 79 | /** 80 | * 排序 81 | * 82 | * @param keyExtractor 属性 83 | * @param desc 是否倒序 84 | * @param nullFirst 是否null值前置 85 | */ 86 | public > Sorter sort(Function keyExtractor, boolean desc, boolean nullFirst) { 87 | return sort(true, keyExtractor, desc, nullFirst); 88 | } 89 | 90 | 91 | /** 92 | * 设置null前置 93 | */ 94 | public Sorter nullFirst(boolean nullFirst) { 95 | this.nullFirst = nullFirst; 96 | return this; 97 | } 98 | 99 | /** 100 | * 追加排序 101 | * 102 | * @param keyExtractor 属性 103 | * @param keyComparator 排序器 104 | */ 105 | public > Sorter then(Function keyExtractor, Comparator keyComparator) { 106 | return then(Comparator.comparing(keyExtractor, keyComparator), true); 107 | } 108 | 109 | /** 110 | * 追加排序 111 | * 112 | * @param otherComparator 其他比较器 113 | * @param nullFirst null值前置 114 | */ 115 | public Sorter then(Comparator otherComparator, boolean nullFirst) { 116 | Comparator realOtherComparator = Sorter.nullOrder(nullFirst).apply(otherComparator); 117 | return then(realOtherComparator); 118 | } 119 | 120 | /** 121 | * 追加排序器 122 | * 123 | * @param otherComparator 其他比较器 124 | */ 125 | public Sorter then(Comparator otherComparator) { 126 | if (Objects.isNull(comparator)) { 127 | comparator = otherComparator; 128 | } else { 129 | comparator = comparator.thenComparing(otherComparator); 130 | } 131 | return this; 132 | } 133 | 134 | /** 135 | * 排序 136 | * 137 | * @param keyExtractor 属性 138 | * @param keyComparator 比较器 139 | */ 140 | public > Sorter sort(Function keyExtractor, Comparator keyComparator) { 141 | return then(Comparator.comparing(keyExtractor, keyComparator)); 142 | } 143 | 144 | @Override 145 | public > Sorter desc(boolean condition, Function keyExtractor, boolean nullFirst) { 146 | return sort(condition, keyExtractor, true, nullFirst); 147 | } 148 | 149 | @Override 150 | public Sorter desc(boolean condition, Comparator comparator, boolean nullFirst) { 151 | return sort(condition, comparator::compare, true, nullFirst); 152 | } 153 | 154 | @Override 155 | public > Sorter asc(boolean condition, Function keyExtractor, boolean nullFirst) { 156 | return sort(condition, keyExtractor, false, nullFirst); 157 | } 158 | 159 | @Override 160 | public Sorter asc(boolean condition, Comparator comparator, boolean nullFirst) { 161 | return sort(condition, comparator::compare, false, nullFirst); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/assist/Spliterators.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.assist; 2 | 3 | import com.taowater.ztream.Ztream; 4 | import lombok.experimental.UtilityClass; 5 | 6 | import java.util.*; 7 | import java.util.Map.Entry; 8 | import java.util.function.Consumer; 9 | import java.util.function.Function; 10 | import java.util.stream.Collector; 11 | 12 | /** 13 | * 分割器相关 14 | * 15 | * @author zhu56 16 | */ 17 | @UtilityClass 18 | public class Spliterators { 19 | 20 | // 分组用分割器 21 | public static class GroupSpliterator implements Spliterator> { 22 | /** 23 | * 源分割器 24 | */ 25 | private final Spliterator sourceSpliterator; 26 | /** 27 | * 分族元素容器 28 | */ 29 | private final Map> groups = new HashMap<>(); 30 | private Iterator>> groupIterator; 31 | 32 | private final Function funK; 33 | private final Function funV; 34 | private final Collector downstream; 35 | 36 | public GroupSpliterator(Spliterator sourceSpliterator, 37 | Function funK, 38 | Function funV, 39 | Collector downstream 40 | ) { 41 | this.sourceSpliterator = sourceSpliterator; 42 | this.funK = funK; 43 | this.funV = funV; 44 | this.downstream = downstream; 45 | } 46 | 47 | @Override 48 | public boolean tryAdvance(Consumer> action) { 49 | if (groupIterator == null) { 50 | sourceSpliterator.forEachRemaining(item -> { 51 | K key = null; 52 | if (Objects.nonNull(item)) { 53 | key = funK.apply(item); 54 | } 55 | groups.computeIfAbsent(key, k -> new ArrayList<>()).add(item); 56 | }); 57 | groupIterator = groups.entrySet().iterator(); 58 | } 59 | if (groupIterator.hasNext()) { 60 | Map.Entry newEntry = Functions.entryKeyValue(groupIterator.next(), k -> k, v -> Ztream.of(v).map(i -> { 61 | V iv = null; 62 | if (Objects.nonNull(i)) { 63 | iv = funV.apply(i); 64 | } 65 | return iv; 66 | }).collect(downstream)); 67 | action.accept(newEntry); 68 | return true; 69 | } 70 | return false; 71 | } 72 | 73 | @Override 74 | public Spliterator> trySplit() { 75 | return null; // 不支持并行拆分 76 | } 77 | 78 | @Override 79 | public long estimateSize() { 80 | return sourceSpliterator.estimateSize(); 81 | } 82 | 83 | @Override 84 | public int characteristics() { 85 | return sourceSpliterator.characteristics() & ~(Spliterator.SIZED | Spliterator.SUBSIZED); 86 | } 87 | } 88 | 89 | // 追加分割器 90 | public static class AppendSpliterator implements Spliterator { 91 | /** 92 | * 源分割器 93 | */ 94 | private Spliterator left; 95 | private Spliterator right; 96 | private int characteristics; 97 | private long size; 98 | 99 | @SuppressWarnings("unchecked") 100 | public AppendSpliterator(Spliterator left, 101 | Spliterator right 102 | ) { 103 | 104 | this.left = (Spliterator) left; 105 | this.right = (Spliterator) right; 106 | this.characteristics = left.characteristics() & right.characteristics() & (ORDERED | SIZED | SUBSIZED); 107 | this.size = left.estimateSize() + right.estimateSize(); 108 | if (this.size < 0) { 109 | this.size = Long.MAX_VALUE; 110 | this.characteristics &= (~SIZED) & (~SUBSIZED); 111 | } 112 | } 113 | 114 | @Override 115 | public boolean tryAdvance(Consumer action) { 116 | if (left != null) { 117 | if (left.tryAdvance(action)) { 118 | if (size > 0 && size != Long.MAX_VALUE) { 119 | size--; 120 | } 121 | return true; 122 | } 123 | left = null; 124 | } 125 | return right.tryAdvance(action); 126 | } 127 | 128 | @Override 129 | public void forEachRemaining(Consumer action) { 130 | 131 | if (left != null) { 132 | left.forEachRemaining(action); 133 | } 134 | if (right != null) { 135 | right.forEachRemaining(action); 136 | } 137 | } 138 | 139 | @Override 140 | public Spliterator trySplit() { 141 | if (left == null) { 142 | return right.trySplit(); 143 | } 144 | Spliterator s = left; 145 | left = null; 146 | return s; 147 | } 148 | 149 | @Override 150 | public long estimateSize() { 151 | if (left == null) { 152 | return right == null ? 0 : right.estimateSize(); 153 | } 154 | return size; 155 | } 156 | 157 | @Override 158 | public int characteristics() { 159 | return characteristics; 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ztream 2 | 3 | 17 | 18 | Java Stream 增强 19 | 20 | ### 🍊Maven 21 | 22 | ```xml 23 | 24 | 25 | io.github.taowater 26 | ztream 27 | LATEST 28 | 29 | ``` 30 | ### 废话 31 | 32 | Java8流操作的出现使得在业务中处理集合的一些操作逻辑变得明晰起来 33 | 但同时它带来一些问题,例如: 34 | * 一些必要api缺失(不能按某属性去重、遍历不能带上下标等) 35 | * 部分reduce操作如映射分组收集写法晦涩,样板代码过多 36 | * 自带分组映射方法对空元素的不友好 37 | 38 | 为了解决这些实际开发中遇到的痛点,我捣鼓出了这个东西,可以进一步改善流的操作体验,更快出活,~~更好摸鱼!~~ 39 | 40 | 另外,高版本的Jdk已经对上述一些问题做出一定程度的优化,自22之后更是推出了流收集器Gatherer来允许一些自定义的中间操作 41 | 但Ztream中一些常用实用api仍有其使用价值,尤其是在仍有相当人高举"你发任你发,我用Java8"大旗的当下。 42 | 43 | 最后,这个小库没有什么很高深的东西,无非是一些封装罢了。只是我自己一路完善过来,敝帚自珍,把他搬了上来。 44 | 他可能不够完美,但是它确实让我更好地crud,也希望可以帮到大家。 45 | 对流操作的一些库,在我冲浪参考的过程中,还有这些: 46 | * streamex https://github.com/amaembo/streamex 47 | * JDFrame https://github.com/burukeYou/JDFrame 48 | * seq https://github.com/wolray/seq 49 | * stream-query https://github.com/dromara/stream-query 50 | 51 | 若拙库可取则取之,如其不才,君可自取。 52 | 53 | [![Star History Chart](https://api.star-history.com/svg?repos=taowater/ztream&type=Date)](https://star-history.com/#taowater/ztream&Date) 54 | 55 | ### 示例 56 | 57 | #### 收集 58 | 59 | ```java 60 | // stream 61 | List userNames = Stream.of(users).map(User::getName).collect(Collectors.toList()); 62 | // ztream(java16+stream已支持) 63 | List userNames = Ztream.of(users).map(User::getName).toList(); 64 | // ztream 65 | List userNames = Ztream.of(users).collect(User::getName); 66 | // 收集为set 67 | Set userNames = Ztream.of(users).toSet(User::getName); 68 | // 制定收集集合类型 69 | Set userNames = Ztream.of(users).collect(User::getName, TreeSet::new); 70 | ``` 71 | 72 | #### 分组/映射 73 | 74 | ```java 75 | // stream value或key为空会报异常 76 | Map map = Stream.of(list).collect(Collectors.toMap(Student::getName, Student::getAge)); 77 | // ztream value或key允许为空 78 | Map map = Ztream.of(list).toMap(Student::getName, Student::getAge); 79 | // 指定map类型 80 | Map map = Ztream.of(list).toMap(Student::getName, Student::getAge, LinkedHashMap::new); 81 | // stream 82 | Map> group = Stream.of(list).collect(Collectors.groupingBy(Student::getName)); 83 | // ztream 84 | Map> group = Ztream.of(list).groupBy(Student::getName); 85 | 86 | // v0.1.0支持分组和映射的中间操作 87 | Ztream.of(list) 88 | .hash(Student::getName, Student::getAge) 89 | .flip() // 对key value进行反转 90 | .forEach((k, v) -> { 91 | // doSomeThing 92 | }); 93 | 94 | ``` 95 | 96 | ##### 带索引的上下文 97 | 98 | ```java 99 | // forEach 100 | Ztream.(list).forEach((e, i) -> { 101 | // doSomeThing 102 | }); 103 | 104 | Ztream.(list).peek((e, i) -> { 105 | // doSomeThing 106 | }).other 107 | 108 | Ztream.(list).map((e, i) -> { 109 | // doSomeThing 110 | return o; 111 | }).other 112 | ``` 113 | 114 | #### 字符拼接 115 | 116 | ```java 117 | // 默认[,]分隔,输出为所有名字按逗号分隔,示例结果:"刘备,关羽,张飞" 118 | String str = Ztream.of(list).join(Student::getName); 119 | 120 | // 指定分隔符,结果:"刘备#关羽#张飞" 121 | String str = Ztream.of(list).join(Student::getName, "#"); 122 | 123 | // 指定分隔符以及前后缀,结果:"[刘备#关羽#张飞]" 124 | String str = Ztream.of(list).join(Student::getName, "#", "[", "]"); 125 | ``` 126 | 127 | ##### 数字及统计 128 | 129 | ```java 130 | // ztream - 需要该属性为Number类型 131 | // 最大年龄 132 | Integer max = Ztream.of(list).max(Student::getAge); 133 | // 最小年龄 134 | Integer min = Ztream.of(list).min(Student::getAge); 135 | // 所有年龄之和 136 | Integer sum = Ztream.of(list).sum(Student::getAge); 137 | // 年龄平均值 138 | Integer avg = Ztream.of(list).avg(Student::getAge); 139 | // 取得最大年龄该学生对象 140 | Student maxAgeStudent = Ztream.of(list).maxBy(Student::getAge); 141 | ``` 142 | 143 | #### 过滤 144 | 145 | ```java 146 | // 类似mybatis-plus的操作 147 | List list = Ztream.of(list) 148 | .eq(Student::getAge, 34) // 年龄等于34 149 | .like(Student::getName, "朱") // 姓名为朱开头 150 | .ge(Student::getScore, 60) // 分数达于等于60 151 | .lt(flag, Student::getScore, 80) // 分数达于等于60, 当某条件为真时才拼接该条件 152 | // 或逻辑拼接 153 | .or(w -> w 154 | .like(Student::getName, "刘") 155 | // 可使用基础筛选方法 156 | ) 157 | // 且逻辑拼接 158 | .and(w -> w 159 | .like(Student::getName, "刘") 160 | // 可使用基础筛选方法 161 | ) 162 | .toList(); 163 | ``` 164 | 165 | #### 排序 166 | ```java 167 | // 按年龄升序 168 | List list = Ztream.of(list).asc(Student::getAge).toList(); 169 | // 按年龄逆序 170 | List list = Ztream.of(list).desc(Student::getAge).toList(); 171 | // 洗牌 172 | List list = Ztream.of(list).shuffle().toList(); 173 | 174 | // 先按年龄降序(null排前),年龄相同按名称升序(null排后) 175 | List list = Ztream.of(list) 176 | .sort(r -> r 177 | .desc(flag, Student::getAge, true) // 当某条件为真时才应用该排序操作 178 | .asc(Student::getName, false) 179 | ).toList(); 180 | ``` 181 | 182 | 其他更多方法尝试Ztream.of(obj)点出来看看吧 183 | 184 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/GroupBy.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op; 2 | 3 | import com.taowater.ztream.assist.ExCollectors; 4 | 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.function.Function; 10 | import java.util.function.Supplier; 11 | import java.util.stream.Collector; 12 | import java.util.stream.Collectors; 13 | import java.util.stream.Stream; 14 | 15 | /** 16 | * 分组操作 17 | * 18 | * @author Zhu56 19 | * @since 0.0.1 20 | */ 21 | @SuppressWarnings("unused") 22 | public interface GroupBy extends Stream { 23 | 24 | /** 25 | * 分组-缺省值类型、Map类型及组集合类型,默认为元素本身、HashMap及ArrayList 26 | * 27 | * @param funK funK 28 | * @return 分组结果 29 | */ 30 | default Map> groupBy(Function funK) { 31 | return this.groupBy(funK, Function.identity()); 32 | } 33 | 34 | /** 35 | * 分组-缺省值类型及组集合类型,默认为元素本身及ArrayList 36 | * 37 | * @param funK 分组依据 38 | * @param mapFactory map工厂 39 | * @return 分组结果 40 | */ 41 | default >> M groupBy(Function funK, Supplier mapFactory) { 42 | return this.groupBy(funK, mapFactory, Collectors.toList()); 43 | } 44 | 45 | /** 46 | * 分组-缺省值类型及Map类型,默认为元素本身及HashMap 47 | * 48 | * @param funK 分组依据 49 | * @param downstream 下游 50 | * @return 分组结果 51 | */ 52 | @SuppressWarnings("unchecked") 53 | default > M groupBy(Function funK, Collector downstream) { 54 | return (M) this.groupBy(funK, Function.identity(), HashMap::new, downstream); 55 | } 56 | 57 | /** 58 | * 集团 59 | * 分组-缺省值类型,默认为元素本身 60 | * 61 | * @param funK 分组依据 62 | * @param mapFactory map工厂 63 | * @param downstream 下游 64 | * @return 分组结果 65 | */ 66 | default > M groupBy(Function funK, Supplier mapFactory, Collector downstream) { 67 | return this.groupBy(funK, Function.identity(), mapFactory, downstream); 68 | } 69 | 70 | /** 71 | * 分组-缺省Map类型及组集合类型,默认为HashMap及ArrayList 72 | * 73 | * @param funK 分组依据 74 | * @param funV 值依据 75 | * @return 分组结果 76 | */ 77 | default Map> groupBy(Function funK, Function funV) { 78 | return this.groupBy(funK, funV, HashMap::new); 79 | } 80 | 81 | /** 82 | * 分组-缺省组集合类型,默认为ArrayList 83 | * 84 | * @param funK 分组依据 85 | * @param funV 值依据 86 | * @param mapFactory 提供的map 87 | * @return 分组结果 88 | */ 89 | default >> M groupBy(Function funK, Function funV, Supplier mapFactory) { 90 | return this.groupBy(funK, funV, mapFactory, Collectors.toList()); 91 | } 92 | 93 | /** 94 | * 分组-缺省Map类型,默认为HashMap 95 | * 96 | * @param funK 分组依据 97 | * @param funV 值依据 98 | * @param downstream 下游操作(组集合的类型) 99 | * @return 分组结果 100 | */ 101 | @SuppressWarnings("unchecked") 102 | default > M groupBy(Function funK, Function funV, Collector downstream) { 103 | return (M) this.groupBy(funK, funV, HashMap::new, downstream); 104 | } 105 | 106 | /** 107 | * 分组 108 | * 本方法是其余分组方法的基础,其余方法都是常见情形或默认缺省的重载 109 | * M> 四个参数中:funK决定K;funV决定V;mapFactory决定M;downstream决定S 110 | * 111 | * @param funK 分组依据 112 | * @param funV 值依据 113 | * @param mapFactory 提供的map 114 | * @param downstream 下游操作(组集合的类型) 115 | * @return 分组结果 116 | */ 117 | default > M groupBy(Function funK, Function funV, Supplier mapFactory, Collector downstream) { 118 | return this.collect(ExCollectors.groupingBy(funK, mapFactory, ExCollectors.mapping(funV, downstream))); 119 | } 120 | 121 | /** 122 | * 两层分组 123 | * 124 | * @param funK 一重键 125 | * @param funK2 二重键 126 | * @return 分组结果 127 | */ 128 | default >>> M groupBilayer(Function funK, Function funK2) { 129 | return groupBilayer(funK, funK2, Function.identity()); 130 | } 131 | 132 | /** 133 | * 两层分组 134 | * 135 | * @param funK 一重键 136 | * @param funK2 二重键 137 | * @param funV 值属性 138 | * @return 分组结果 139 | */ 140 | @SuppressWarnings("unchecked") 141 | default >>> M groupBilayer(Function funK, Function funK2, Function funV) { 142 | return (M) this.reduce(new HashMap>>(), (map, e) -> { 143 | Map> subMap = map.computeIfAbsent(funK.apply(e), k -> new HashMap<>()); 144 | List list = subMap.computeIfAbsent(funK2.apply(e), k -> new ArrayList<>()); 145 | list.add(funV.apply(e)); 146 | return map; 147 | }, (map1, map2) -> { 148 | map1.forEach((k, v) -> { 149 | Map> v2 = map2.get(k); 150 | map1.merge(k, v2, (o, n) -> { 151 | o.forEach((sk, sv) -> { 152 | List sv2 = v2.get(sk); 153 | o.merge(sk, sv2, (so, sn) -> { 154 | so.addAll(sn); 155 | return so; 156 | }); 157 | }); 158 | return o; 159 | }); 160 | }); 161 | return map1; 162 | }); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/math/Math.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op.math; 2 | 3 | 4 | import com.taowater.taol.core.function.Function1; 5 | import com.taowater.taol.core.util.NumberUtil; 6 | import com.taowater.ztream.Any; 7 | import com.taowater.ztream.IZtream; 8 | import com.taowater.ztream.assist.ExCollectors; 9 | import lombok.var; 10 | 11 | import java.math.BigDecimal; 12 | import java.util.Objects; 13 | 14 | /** 15 | * 数学统计相关 16 | * 17 | * @author zhu56 18 | * @since 0.0.1 19 | */ 20 | public interface Math> extends IZtream { 21 | 22 | /** 23 | * 累加 24 | * 25 | * @param fun 属性 26 | * @return 和 27 | */ 28 | default N sum(Function1 fun) { 29 | return sum(fun, null); 30 | } 31 | 32 | /** 33 | * 累加 34 | * 35 | * @param fun 属性方法引用 36 | * @param defaultValue 默认值 37 | * @return 和 38 | */ 39 | default N sum(Function1 fun, N defaultValue) { 40 | var result = filter(Objects::nonNull) 41 | .map(fun) 42 | .map(NumberUtil::toBigDecimal) 43 | .reduce((a, b) -> Any.of(a).map(e -> e.add(Any.of(b).orElse(BigDecimal.ZERO))).orElse(BigDecimal.ZERO)) 44 | .map(b -> NumberUtil.getValue(b, fun)); 45 | if (result.isPresent()) { 46 | return result.get(); 47 | } 48 | return defaultValue; 49 | } 50 | 51 | /** 52 | * 按属性取最小的元素 53 | * 54 | * @param fun 属性 55 | * @param nullMin null视为最小 56 | * @return {@link T } 57 | */ 58 | default > Any minBy(Function1 fun, boolean nullMin) { 59 | return this.collect(ExCollectors.peak(fun, nullMin)).getMin(); 60 | } 61 | 62 | /** 63 | * 按属性取最小的元素 64 | * 65 | * @param fun 属性 66 | * @return {@link T } 67 | */ 68 | default > Any minBy(Function1 fun) { 69 | return this.minBy(fun, true); 70 | } 71 | 72 | /** 73 | * 按属性取最大的元素 74 | * 75 | * @param fun 属性 76 | * @param nullMin null视为最小 77 | * @return {@link T } 78 | */ 79 | default > Any maxBy(Function1 fun, boolean nullMin) { 80 | return this.collect(ExCollectors.peak(fun, nullMin)).getMax(); 81 | } 82 | 83 | /** 84 | * 按属性取最大的元素 85 | * 86 | * @param fun 属性 87 | * @return {@link T } 88 | */ 89 | default > Any maxBy(Function1 fun) { 90 | return this.maxBy(fun, true); 91 | } 92 | 93 | /** 94 | * 最大 95 | * 96 | * @return 结果 97 | */ 98 | default Any max() { 99 | return this.max(true); 100 | } 101 | 102 | /** 103 | * 最大 104 | * 105 | * @param nullMin null视为最小 106 | * @return 结果 107 | */ 108 | @SuppressWarnings("unchecked") 109 | default Any max(boolean nullMin) { 110 | return this.collect(ExCollectors.peak( 111 | (a, b) -> { 112 | if (a instanceof Comparable) { 113 | return ((Comparable) a).compareTo(b); 114 | } 115 | return a.toString().compareTo(b.toString()); 116 | }, nullMin 117 | )).getMax(); 118 | } 119 | 120 | /** 121 | * 最大值 122 | * 123 | * @param fun 函数 124 | * @return 最大值 125 | */ 126 | default > N max(Function1 fun) { 127 | return max(fun, null); 128 | } 129 | 130 | /** 131 | * 最大值 132 | * 133 | * @param fun 属性 134 | * @param defaultValue 默认值 135 | * @return 最大值 136 | */ 137 | default > N max(Function1 fun, N defaultValue) { 138 | return this.maxBy(fun).get(fun, defaultValue); 139 | } 140 | 141 | /** 142 | * 最小值 143 | * 144 | * @param fun 函数 145 | * @return 最小值 146 | */ 147 | default > N min(Function1 fun) { 148 | return min(fun, null); 149 | } 150 | 151 | /** 152 | * 最小 153 | * 154 | * @return 结果 155 | */ 156 | default Any min() { 157 | return this.min(true); 158 | } 159 | 160 | /** 161 | * 最小 162 | * 163 | * @param nullMin null视为最小 164 | * @return 结果 165 | */ 166 | @SuppressWarnings("unchecked") 167 | default Any min(boolean nullMin) { 168 | return this.collect(ExCollectors.peak( 169 | (a, b) -> { 170 | if (a instanceof Comparable) { 171 | return ((Comparable) a).compareTo(b); 172 | } 173 | return a.toString().compareTo(b.toString()); 174 | }, nullMin 175 | )).getMin(); 176 | } 177 | 178 | /** 179 | * 最小值 180 | * 181 | * @param fun 属性 182 | * @param defaultValue 默认值 183 | * @return 最小值 184 | */ 185 | default > N min(Function1 fun, N defaultValue) { 186 | return this.minBy(fun).get(fun, defaultValue); 187 | } 188 | 189 | /** 190 | * 平均值 191 | * 192 | * @param fun 属性 193 | * @param defaultValue 默认值 194 | * @param nullCount null是否计数 195 | * @return 平均值 196 | */ 197 | default N avg(Function1 fun, N defaultValue, boolean nullCount) { 198 | var result = collect(ExCollectors.avg(fun, nullCount)); 199 | return Any.of(result).orElse(defaultValue); 200 | } 201 | 202 | /** 203 | * 平均值 204 | * 205 | * @param fun 属性 206 | * @param defaultValue 默认值 207 | * @return 平均值 208 | */ 209 | default N avg(Function1 fun, N defaultValue) { 210 | return avg(fun, defaultValue, true); 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/filter/Compare.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op.filter; 2 | 3 | import java.util.Collection; 4 | import java.util.function.Function; 5 | import java.util.function.Predicate; 6 | 7 | /** 8 | * 比较操作 9 | * 10 | * @author zhu56 11 | */ 12 | @SuppressWarnings("unused") 13 | public interface Compare extends CompareX { 14 | 15 | W filter(Predicate predicate); 16 | 17 | /** 18 | * 过滤 19 | * 20 | * @param fun 属性 21 | * @param predicate 判断函数 22 | */ 23 | default W filter(Function fun, Predicate predicate) { 24 | return filter(true, fun, predicate); 25 | } 26 | 27 | /** 28 | * 等值操作 29 | * 30 | * @param fun 属性 31 | * @param value 值 32 | */ 33 | default W eq(Function fun, V value) { 34 | return eq(true, fun, value); 35 | } 36 | 37 | 38 | /** 39 | * in操作 40 | * 41 | * @param fun 属性 42 | * @param values 值 43 | */ 44 | default W in(Function fun, Collection values) { 45 | return in(true, fun, values); 46 | } 47 | 48 | /** 49 | * in操作 50 | * 51 | * @param fun 属性 52 | * @param values 值 53 | */ 54 | @SuppressWarnings("unchecked") 55 | default W in(Function fun, V... values) { 56 | return in(true, fun, values); 57 | } 58 | 59 | /** 60 | * 过滤在指定集合中的元素 61 | * 62 | * @param c c 63 | */ 64 | default W in(Collection c) { 65 | return in(true, c); 66 | } 67 | 68 | /** 69 | * 过滤在指定集合中的元素 70 | * 71 | * @param c c 72 | */ 73 | @SuppressWarnings("all") 74 | default W in(T... c) { 75 | return in(true, c); 76 | } 77 | 78 | /** 79 | * 过滤不在指定集合中的元素 80 | * 81 | * @param c c 82 | */ 83 | default W notIn(Collection c) { 84 | return notIn(true, c); 85 | } 86 | 87 | /** 88 | * 过滤不在指定集合中的元素 89 | * 90 | * @param values 指定值 91 | */ 92 | @SuppressWarnings("all") 93 | default W notIn(T... values) { 94 | return notIn(true, values); 95 | } 96 | 97 | /** 98 | * notin操作 99 | * 100 | * @param fun 属性 101 | * @param values 值 102 | */ 103 | default W notIn(Function fun, Collection values) { 104 | return notIn(true, fun, values); 105 | } 106 | 107 | /** 108 | * notin操作 109 | * 110 | * @param fun 属性 111 | * @param values 值 112 | */ 113 | @SuppressWarnings("unchecked") 114 | default W notIn(Function fun, V... values) { 115 | return notIn(true, fun, values); 116 | } 117 | 118 | /** 119 | * 过滤为空的元素 120 | */ 121 | default W isNull() { 122 | return isNull(true); 123 | } 124 | 125 | /** 126 | * 过滤元素非空 127 | */ 128 | default W nonNull() { 129 | return nonNull(true); 130 | } 131 | 132 | /** 133 | * 过滤某属性为空的元素 134 | * 135 | * @param fun 函数 136 | */ 137 | default W isNull(Function fun) { 138 | return isNull(true, fun); 139 | } 140 | 141 | 142 | /** 143 | * 过滤某属性不为空的元素 144 | * 145 | * @param fun 属性 146 | */ 147 | default W nonNull(Function fun) { 148 | return nonNull(true, fun); 149 | } 150 | 151 | /** 152 | * 过滤某字符串属性为空的元素 153 | * 154 | * @param fun 属性 155 | */ 156 | default W isEmpty(Function fun) { 157 | return isEmpty(true, fun); 158 | } 159 | 160 | /** 161 | * 过滤某字符串属性不为空的元素 162 | * 163 | * @param fun 属性 164 | */ 165 | default W nonEmpty(Function fun) { 166 | return nonEmpty(true, fun); 167 | } 168 | 169 | /** 170 | * 过滤某字符串属性为空白的元素 171 | * 172 | * @param fun 属性 173 | */ 174 | default W isBlank(Function fun) { 175 | return isBlank(true, fun); 176 | } 177 | 178 | /** 179 | * 过滤某字符串属性不为空白的元素 180 | * 181 | * @param fun 属性 182 | */ 183 | default W nonBlank(Function fun) { 184 | return nonBlank(true, fun); 185 | } 186 | 187 | /** 188 | * 小于 189 | * 190 | * @param fun 属性 191 | * @param value 值 192 | */ 193 | default > W lt(Function fun, N value) { 194 | return lt(true, fun, value); 195 | } 196 | 197 | /** 198 | * 小于等于 199 | * 200 | * @param fun 属性 201 | * @param value 值 202 | */ 203 | default > W le(Function fun, N value) { 204 | return le(true, fun, value); 205 | } 206 | 207 | /** 208 | * 大于 209 | * 210 | * @param fun 属性 211 | * @param value 值 212 | */ 213 | default > W gt(Function fun, N value) { 214 | return gt(true, fun, value); 215 | } 216 | 217 | /** 218 | * 大于等于 219 | * 220 | * @param fun 属性 221 | * @param value 值 222 | */ 223 | default > W ge(Function fun, N value) { 224 | return ge(true, fun, value); 225 | } 226 | 227 | /** 228 | * 区间 229 | * 230 | * @param fun 属性 231 | * @param leftValue 左值 232 | * @param rightValue 右值 233 | */ 234 | default > W between(Function fun, N leftValue, N rightValue) { 235 | return between(true, fun, leftValue, rightValue); 236 | } 237 | 238 | /** 239 | * 过滤指定字符属性以value开头的元素 240 | * 241 | * @param fun 属性 242 | * @param value 值 243 | */ 244 | default W rightLike(Function fun, String value) { 245 | return rightLike(true, fun, value); 246 | } 247 | 248 | default W like(Function fun, String value) { 249 | return like(true, fun, value); 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | io.github.taowater 9 | ztream 10 | ${revision} 11 | jar 12 | 13 | ztream 14 | Java Stream 增强 15 | 16 | 17 | Zhu56 18 | 248771337@qq.com 19 | 20 | 21 | https://github.com/taowater/ztream 22 | 23 | 24 | 25 | 0.2.3 26 | UTF-8 27 | 8 28 | 3.13.0 29 | 3.3.1 30 | 3.7.0 31 | 3.2.4 32 | 0.7.0 33 | 1.18.42 34 | 5.11.4 35 | 0.2.2 36 | 37 | 38 | 39 | 40 | 41 | org.projectlombok 42 | lombok 43 | ${lombok.version} 44 | 45 | 46 | io.github.taowater 47 | taol-core 48 | ${taol.version} 49 | 50 | 51 | 52 | org.junit.jupiter 53 | junit-jupiter-engine 54 | ${junit.version} 55 | test 56 | 57 | 58 | 59 | 60 | 61 | MIT License 62 | https://github.com/taowater/ztream?tab=MIT-1-ov-file 63 | repo 64 | 65 | 66 | 67 | 68 | master 69 | https://github.com/taowater/ztream 70 | scm:git:git@github.com:taowater/ztream.git 71 | scm:git:git@github.com:taowater/ztream.git 72 | 73 | 74 | 75 | 76 | central 77 | https://central.sonatype.com 78 | 79 | 80 | 81 | 82 | 83 | 84 | org.apache.maven.plugins 85 | maven-compiler-plugin 86 | ${maven-compiler-plugin.version} 87 | 88 | ${java.version} 89 | ${java.version} 90 | -Xlint:unchecked 91 | 92 | 93 | 94 | 95 | org.apache.maven.plugins 96 | maven-javadoc-plugin 97 | ${maven-javadoc-plugin.version} 98 | 99 | 100 | package 101 | 102 | jar 103 | 104 | 105 | 106 | 107 | 108 | -Xdoclint:none -J-Dfile.encoding=utf-8 109 | 110 | 111 | 112 | 113 | org.apache.maven.plugins 114 | maven-source-plugin 115 | ${maven-source-plugin.version} 116 | 117 | true 118 | 119 | 120 | 121 | compile 122 | 123 | jar 124 | 125 | 126 | 127 | 128 | 129 | 130 | org.apache.maven.plugins 131 | maven-gpg-plugin 132 | ${maven-gpg-plugin.version} 133 | 134 | 135 | verify 136 | 137 | sign 138 | 139 | 140 | 141 | 142 | 143 | 144 | --pinentry-mode 145 | loopback 146 | 147 | 148 | 149 | 150 | org.sonatype.central 151 | central-publishing-maven-plugin 152 | ${central-publishing-maven-plugin.version} 153 | true 154 | 155 | central 156 | 157 | 158 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/IZtream.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream; 2 | 3 | 4 | import java.util.Comparator; 5 | import java.util.Iterator; 6 | import java.util.Optional; 7 | import java.util.Spliterator; 8 | import java.util.function.*; 9 | import java.util.stream.*; 10 | 11 | /** 12 | * ztream 接口 13 | * 14 | * @author Zhu56 15 | */ 16 | public interface IZtream> extends Stream, Iterable { 17 | 18 | /** 19 | * 获取原始流 20 | */ 21 | Stream stream(); 22 | 23 | 24 | /** 25 | * 将标准流包装为增强流 26 | * 27 | * @param stream 流 28 | * @return 包装的结果 29 | */ 30 | S ztream(Stream stream); 31 | 32 | @Override 33 | default S filter(Predicate predicate) { 34 | return ztream(stream().filter(predicate)); 35 | } 36 | 37 | @Override 38 | default IntStream mapToInt(ToIntFunction mapper) { 39 | return stream().mapToInt(mapper); 40 | } 41 | 42 | @Override 43 | default LongStream mapToLong(ToLongFunction mapper) { 44 | return stream().mapToLong(mapper); 45 | } 46 | 47 | @Override 48 | default DoubleStream mapToDouble(ToDoubleFunction mapper) { 49 | return stream().mapToDouble(mapper); 50 | } 51 | 52 | @Override 53 | default IntStream flatMapToInt(Function mapper) { 54 | return stream().flatMapToInt(mapper); 55 | } 56 | 57 | @Override 58 | default LongStream flatMapToLong(Function mapper) { 59 | return stream().flatMapToLong(mapper); 60 | } 61 | 62 | @Override 63 | default DoubleStream flatMapToDouble(Function mapper) { 64 | return stream().flatMapToDouble(mapper); 65 | } 66 | 67 | @Override 68 | default S distinct() { 69 | return ztream(stream().distinct()); 70 | } 71 | 72 | @Override 73 | default S sorted() { 74 | return ztream(stream().sorted()); 75 | } 76 | 77 | @Override 78 | default S sorted(Comparator comparator) { 79 | return ztream(stream().sorted(comparator)); 80 | } 81 | 82 | @Override 83 | @SuppressWarnings("all") 84 | default S peek(Consumer action) { 85 | return ztream(stream().peek(action)); 86 | } 87 | 88 | @Override 89 | default S limit(long maxSize) { 90 | return ztream(stream().limit(maxSize)); 91 | } 92 | 93 | @Override 94 | default S skip(long n) { 95 | return ztream(stream().skip(n)); 96 | } 97 | 98 | @Override 99 | default void forEach(Consumer action) { 100 | stream().forEach(action); 101 | } 102 | 103 | @Override 104 | default void forEachOrdered(Consumer action) { 105 | stream().forEachOrdered(action); 106 | } 107 | 108 | @Override 109 | default Object[] toArray() { 110 | return stream().toArray(); 111 | } 112 | 113 | @Override 114 | default A[] toArray(IntFunction generator) { 115 | return stream().toArray(generator); 116 | } 117 | 118 | @Override 119 | default T reduce(T identity, BinaryOperator accumulator) { 120 | return stream().reduce(identity, accumulator); 121 | } 122 | 123 | @Override 124 | default Optional reduce(BinaryOperator accumulator) { 125 | return stream().reduce(accumulator); 126 | } 127 | 128 | @Override 129 | default U reduce(U identity, BiFunction accumulator, BinaryOperator combiner) { 130 | return stream().reduce(identity, accumulator, combiner); 131 | } 132 | 133 | @Override 134 | default R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner) { 135 | return stream().collect(supplier, accumulator, combiner); 136 | } 137 | 138 | @Override 139 | default R collect(Collector collector) { 140 | return stream().collect(collector); 141 | } 142 | 143 | @Override 144 | default Optional min(Comparator comparator) { 145 | return stream().min(comparator); 146 | } 147 | 148 | @Override 149 | default Optional max(Comparator comparator) { 150 | return stream().max(comparator); 151 | } 152 | 153 | @Override 154 | default long count() { 155 | return stream().count(); 156 | } 157 | 158 | @Override 159 | default boolean anyMatch(Predicate predicate) { 160 | return stream().anyMatch(predicate); 161 | } 162 | 163 | @Override 164 | default boolean allMatch(Predicate predicate) { 165 | return stream().allMatch(predicate); 166 | } 167 | 168 | @Override 169 | default boolean noneMatch(Predicate predicate) { 170 | return stream().noneMatch(predicate); 171 | } 172 | 173 | @Override 174 | default Optional findFirst() { 175 | return stream().findFirst(); 176 | } 177 | 178 | /** 179 | * 首个元素 180 | * 181 | * @param throwNpe 是否抛出空指针异常 182 | * @return 结果 183 | */ 184 | default Optional findFirst(boolean throwNpe) { 185 | try { 186 | return stream().findFirst(); 187 | } catch (NullPointerException e) { 188 | if (throwNpe) { 189 | throw e; 190 | } 191 | return Optional.empty(); 192 | } 193 | } 194 | 195 | @Override 196 | default Optional findAny() { 197 | return stream().findAny(); 198 | } 199 | 200 | /** 201 | * 任意一个 202 | * 203 | * @param throwNpe 是否抛出空指针异常 204 | * @return 结果 205 | */ 206 | default Optional findAny(boolean throwNpe) { 207 | try { 208 | return stream().findAny(); 209 | } catch (NullPointerException e) { 210 | if (throwNpe) { 211 | throw e; 212 | } 213 | return Optional.empty(); 214 | } 215 | } 216 | 217 | @Override 218 | default Iterator iterator() { 219 | return stream().iterator(); 220 | } 221 | 222 | @Override 223 | default Spliterator spliterator() { 224 | return stream().spliterator(); 225 | } 226 | 227 | @Override 228 | default boolean isParallel() { 229 | return stream().isParallel(); 230 | } 231 | 232 | @Override 233 | default S sequential() { 234 | return ztream(stream().sequential()); 235 | } 236 | 237 | @Override 238 | default S parallel() { 239 | return ztream(stream().parallel()); 240 | } 241 | 242 | @Override 243 | default S unordered() { 244 | return ztream(stream().unordered()); 245 | } 246 | 247 | @Override 248 | default S onClose(Runnable closeHandler) { 249 | return ztream(stream().onClose(closeHandler)); 250 | } 251 | 252 | @Override 253 | default void close() { 254 | stream().close(); 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/Any.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream; 2 | 3 | 4 | import com.taowater.taol.core.convert.ConvertUtil; 5 | import com.taowater.taol.core.function.Function2; 6 | import com.taowater.taol.core.util.EmptyUtil; 7 | 8 | import java.util.Collection; 9 | import java.util.NoSuchElementException; 10 | import java.util.Objects; 11 | import java.util.function.*; 12 | import java.util.stream.Stream; 13 | 14 | /** 15 | * 自定义Optional 16 | * 17 | * @author Zhu56 18 | */ 19 | @SuppressWarnings({"unused", "unchecked"}) 20 | public final class Any { 21 | 22 | private static final Any EMPTY = new Any<>(null); 23 | 24 | private final T value; 25 | 26 | public static Any empty() { 27 | @SuppressWarnings("unchecked") 28 | Any t = (Any) EMPTY; 29 | return t; 30 | } 31 | 32 | private Any(T value) { 33 | this.value = value; 34 | } 35 | 36 | @SuppressWarnings("unchecked") 37 | public static Any of(T value) { 38 | return Objects.isNull(value) ? (Any) EMPTY : new Any<>(value); 39 | } 40 | 41 | @SuppressWarnings("unchecked") 42 | public static Any of(String value) { 43 | return EmptyUtil.isEmpty(value) ? (Any) EMPTY : new Any<>(value); 44 | } 45 | 46 | public T get() { 47 | if (value == null) { 48 | throw new NoSuchElementException("No value present"); 49 | } 50 | return value; 51 | } 52 | 53 | public U get(Function mapper, U defaultValue) { 54 | Objects.requireNonNull(mapper); 55 | if (!isPresent()) { 56 | return defaultValue; 57 | } 58 | U val = mapper.apply(value); 59 | return Objects.nonNull(val) ? val : defaultValue; 60 | } 61 | 62 | public U get(Function mapper) { 63 | return this.get(mapper, null); 64 | } 65 | 66 | 67 | public boolean isPresent() { 68 | return Objects.nonNull(value); 69 | } 70 | 71 | 72 | public boolean isNull() { 73 | return Objects.isNull(value); 74 | } 75 | 76 | public boolean isEmpty() { 77 | return EmptyUtil.isEmpty(value); 78 | } 79 | 80 | 81 | @SuppressWarnings("all") 82 | public Any ifPresent(Consumer action) { 83 | if (value != null) { 84 | action.accept(value); 85 | } 86 | return this; 87 | } 88 | 89 | @SafeVarargs 90 | public final Any ifPresent(Function function, Consumer... actions) { 91 | V tempValue = function.apply(value); 92 | if (Objects.isNull(tempValue)) { 93 | return this; 94 | } 95 | Stream.of(actions).forEach(action -> action.accept(tempValue)); 96 | return this; 97 | } 98 | 99 | public void ifPresentOrElse(Consumer action, Runnable emptyAction) { 100 | if (value != null) { 101 | action.accept(value); 102 | } else { 103 | emptyAction.run(); 104 | } 105 | } 106 | 107 | public Any filter(Predicate predicate) { 108 | Objects.requireNonNull(predicate); 109 | if (!isPresent()) { 110 | return this; 111 | } 112 | return predicate.test(value) ? this : empty(); 113 | } 114 | 115 | public Any map(Function mapper) { 116 | Objects.requireNonNull(mapper); 117 | if (Objects.isNull(value)) { 118 | return empty(); 119 | } 120 | return Any.of(mapper.apply(value)); 121 | } 122 | 123 | public Any flatMap(Function> mapper) { 124 | Objects.requireNonNull(mapper); 125 | if (!isPresent()) { 126 | return empty(); 127 | } 128 | @SuppressWarnings("unchecked") 129 | Any r = (Any) mapper.apply(value); 130 | return Objects.requireNonNull(r); 131 | } 132 | 133 | /** 134 | * 收集某个集合类型的属性并展开为流 135 | * 136 | * @param mapper 属性 137 | * @return {@link Ztream}<{@link N}> 结果 138 | */ 139 | public > Ztream ztream(Function mapper) { 140 | Objects.requireNonNull(mapper); 141 | return Ztream.of(this.get(mapper)); 142 | } 143 | 144 | public Any or(Supplier> supplier) { 145 | Objects.requireNonNull(supplier); 146 | if (isPresent()) { 147 | return this; 148 | } 149 | @SuppressWarnings("unchecked") 150 | Any r = (Any) supplier.get(); 151 | return Objects.requireNonNull(r); 152 | } 153 | 154 | public Ztream ztream() { 155 | return !isPresent() ? Ztream.empty() : Ztream.of(value); 156 | } 157 | 158 | public T orElse(T other) { 159 | return value != null ? value : other; 160 | } 161 | 162 | public T orElseGet(Supplier supplier) { 163 | return value != null ? value : supplier.get(); 164 | } 165 | 166 | public T orElseThrow() { 167 | if (value == null) { 168 | throw new NoSuchElementException("No value present"); 169 | } 170 | return value; 171 | } 172 | 173 | public T orElseThrow(Supplier exceptionSupplier) throws X { 174 | if (value != null) { 175 | return value; 176 | } 177 | throw exceptionSupplier.get(); 178 | } 179 | 180 | @Override 181 | public boolean equals(Object obj) { 182 | if (this == obj) { 183 | return true; 184 | } 185 | 186 | if (!(obj instanceof Any)) { 187 | return false; 188 | } 189 | 190 | Any other = (Any) obj; 191 | return Objects.equals(value, other.value); 192 | } 193 | 194 | @Override 195 | public int hashCode() { 196 | return Objects.hashCode(value); 197 | } 198 | 199 | @Override 200 | public String toString() { 201 | return isPresent() ? value.toString() : null; 202 | } 203 | 204 | /** 205 | * 转换类型 206 | * 207 | * @param clazz clazz 208 | */ 209 | public Any convert(Class clazz) { 210 | return convert(clazz, ConvertUtil::convert, null); 211 | } 212 | 213 | 214 | /** 215 | * 转换元素类型 216 | * 217 | * @param clazz 类型 218 | * @param convertFun 转换方法 219 | */ 220 | public Any convert(Class clazz, Function2, N> convertFun) { 221 | return convert(clazz, convertFun, null); 222 | } 223 | 224 | /** 225 | * 转换元素类型,按新旧元素入参的消费方法处理元素 226 | * 227 | * @param clazz clazz 228 | * @param consumer 处理函数 229 | */ 230 | public Any convert(Class clazz, BiConsumer consumer) { 231 | return convert(clazz, ConvertUtil::convert, consumer); 232 | } 233 | 234 | public Any convert(Class clazz, Function2, N> convertFun, BiConsumer consumer) { 235 | return map(e -> { 236 | N n = convertFun.apply(e, clazz); 237 | if (Objects.nonNull(consumer)) { 238 | consumer.accept(e, n); 239 | } 240 | return n; 241 | }); 242 | } 243 | 244 | /** 245 | * 获取转换类型后的对象 246 | * 247 | * @param clazz clazz 248 | * @return {@link N} 249 | */ 250 | public N get(Class clazz) { 251 | return this.convert(clazz).orElse(null); 252 | } 253 | 254 | /** 255 | * 偷看 256 | * 257 | * @param consumer 消费者 258 | * @return {@link Any}<{@link T}> 259 | */ 260 | public Any peek(Consumer consumer) { 261 | Objects.requireNonNull(consumer); 262 | if (Objects.nonNull(value)) { 263 | consumer.accept(value); 264 | } 265 | return this; 266 | } 267 | 268 | /** 269 | * 强转元素类型 270 | * 271 | * @param clazz 目标类型 272 | * @return {@link Any}<{@link N}> 273 | */ 274 | public Any cast(Class clazz) { 275 | return map(clazz::cast); 276 | } 277 | 278 | } 279 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/op/filter/ConditionCompare.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.op.filter; 2 | 3 | import com.taowater.taol.core.util.EmptyUtil; 4 | import com.taowater.ztream.Any; 5 | 6 | import java.util.ArrayList; 7 | import java.util.Collection; 8 | import java.util.Objects; 9 | import java.util.function.Function; 10 | import java.util.function.Predicate; 11 | import java.util.stream.Collectors; 12 | import java.util.stream.Stream; 13 | 14 | /** 15 | * 比较操作 16 | * 17 | * @author zhu56 18 | */ 19 | @SuppressWarnings("unchecked") 20 | public interface ConditionCompare { 21 | 22 | W filter(boolean condition, Predicate predicate); 23 | 24 | /** 25 | * 过滤 26 | * 27 | * @param fun 属性 28 | * @param predicate 判断函数 29 | */ 30 | default W filter(boolean condition, Function fun, Predicate predicate) { 31 | return filter(condition, e -> predicate.test(Any.of(e).get(fun))); 32 | } 33 | 34 | /** 35 | * 等值操作 36 | * 37 | * @param fun 属性 38 | * @param value 值 39 | */ 40 | default W eq(boolean condition, Function fun, V value) { 41 | return filter(condition, e -> Objects.equals(value, Any.of(e).get(fun))); 42 | } 43 | 44 | 45 | /** 46 | * in操作 47 | * 48 | * @param fun 属性 49 | * @param values 值 50 | */ 51 | default W in(boolean condition, Function fun, Collection values) { 52 | return filter(condition, fun, Any.of(values).orElse(new ArrayList<>())::contains); 53 | } 54 | 55 | /** 56 | * in操作 57 | * 58 | * @param fun 属性 59 | * @param values 值 60 | */ 61 | @SuppressWarnings("unchecked") 62 | default W in(boolean condition, Function fun, V... values) { 63 | return in(condition, fun, Any.of(values).map(Stream::of).orElse(Stream.empty()).collect(Collectors.toSet())); 64 | } 65 | 66 | /** 67 | * 过滤在指定集合中的元素 68 | * 69 | * @param c c 70 | */ 71 | default W in(boolean condition, Collection c) { 72 | return filter(condition, Any.of(c).orElse(new ArrayList<>())::contains); 73 | } 74 | 75 | /** 76 | * 过滤在指定集合中的元素 77 | * 78 | * @param c c 79 | */ 80 | @SuppressWarnings("all") 81 | default W in(boolean condition, T... values) { 82 | return in(condition, Any.of(values).map(Stream::of).orElse(Stream.empty()).collect(Collectors.toSet())); 83 | } 84 | 85 | /** 86 | * 过滤不在指定集合中的元素 87 | * 88 | * @param c c 89 | */ 90 | default W notIn(boolean condition, Collection c) { 91 | return filter(condition, e -> !Any.of(c).orElse(new ArrayList<>()).contains(e)); 92 | } 93 | 94 | /** 95 | * 过滤不在指定集合中的元素 96 | * 97 | * @param values 指定值 98 | */ 99 | @SuppressWarnings("all") 100 | default W notIn(boolean condition, T... values) { 101 | return notIn(condition, Any.of(values).map(Stream::of).orElse(Stream.empty()).collect(Collectors.toSet())); 102 | } 103 | 104 | /** 105 | * notin操作 106 | * 107 | * @param fun 属性 108 | * @param values 值 109 | */ 110 | default W notIn(boolean condition, Function fun, Collection values) { 111 | return filter(condition, fun, v -> !Any.of(values).orElse(new ArrayList<>()).contains(v)); 112 | } 113 | 114 | /** 115 | * notin操作 116 | * 117 | * @param fun 属性 118 | * @param values 值 119 | */ 120 | @SuppressWarnings("unchecked") 121 | default W notIn(boolean condition, Function fun, V... values) { 122 | return notIn(condition, fun, Any.of(values).map(Stream::of).orElse(Stream.empty()).collect(Collectors.toSet())); 123 | } 124 | 125 | /** 126 | * 过滤为空的元素 127 | */ 128 | default W isNull(boolean condition) { 129 | return filter(condition, Objects::isNull); 130 | } 131 | 132 | /** 133 | * 过滤元素非空 134 | */ 135 | default W nonNull(boolean condition) { 136 | return filter(condition, Objects::nonNull); 137 | } 138 | 139 | /** 140 | * 过滤某属性为空的元素 141 | * 142 | * @param fun 函数 143 | */ 144 | default W isNull(boolean condition, Function fun) { 145 | return filter(condition, fun, Objects::isNull); 146 | } 147 | 148 | 149 | /** 150 | * 过滤某属性不为空的元素 151 | * 152 | * @param fun 属性 153 | */ 154 | default W nonNull(boolean condition, Function fun) { 155 | return filter(condition, fun, Objects::nonNull); 156 | } 157 | 158 | /** 159 | * 过滤某字符串属性为空的元素 160 | * 161 | * @param fun 属性 162 | */ 163 | default W isEmpty(boolean condition, Function fun) { 164 | return filter(condition, fun, EmptyUtil::isEmpty); 165 | } 166 | 167 | /** 168 | * 过滤某字符串属性不为空的元素 169 | * 170 | * @param fun 属性 171 | */ 172 | default W nonEmpty(boolean condition, Function fun) { 173 | return filter(condition, fun, EmptyUtil::isNotEmpty); 174 | } 175 | 176 | /** 177 | * 过滤某字符串属性为空白的元素 178 | * 179 | * @param fun 属性 180 | */ 181 | default W isBlank(boolean condition, Function fun) { 182 | return filter(condition, fun, EmptyUtil::isBlank); 183 | } 184 | 185 | /** 186 | * 过滤某字符串属性不为空白的元素 187 | * 188 | * @param fun 属性 189 | */ 190 | default W nonBlank(boolean condition, Function fun) { 191 | return filter(condition, fun, EmptyUtil::isNotBlank); 192 | } 193 | 194 | /** 195 | * 小于 196 | * 197 | * @param fun 属性 198 | * @param value 值 199 | */ 200 | default > W lt(boolean condition, Function fun, N value) { 201 | Objects.requireNonNull(value); 202 | return filter(condition, e -> { 203 | N v = Any.of(e).get(fun); 204 | if (Objects.isNull(v)) { 205 | return false; 206 | } 207 | return v.compareTo(value) < 0; 208 | }); 209 | } 210 | 211 | /** 212 | * 小于等于 213 | * 214 | * @param fun 属性 215 | * @param value 值 216 | */ 217 | default > W le(boolean condition, Function fun, N value) { 218 | Objects.requireNonNull(value); 219 | return filter(condition, e -> { 220 | N v = Any.of(e).get(fun); 221 | if (Objects.isNull(v)) { 222 | return false; 223 | } 224 | return v.compareTo(value) <= 0; 225 | }); 226 | } 227 | 228 | /** 229 | * 大于 230 | * 231 | * @param fun 属性 232 | * @param value 值 233 | */ 234 | default > W gt(boolean condition, Function fun, N value) { 235 | Objects.requireNonNull(value); 236 | return filter(condition, e -> { 237 | N v = Any.of(e).get(fun); 238 | if (Objects.isNull(v)) { 239 | return false; 240 | } 241 | return v.compareTo(value) > 0; 242 | }); 243 | } 244 | 245 | /** 246 | * 大于等于 247 | * 248 | * @param fun 属性 249 | * @param value 值 250 | */ 251 | default > W ge(boolean condition, Function fun, N value) { 252 | Objects.requireNonNull(value); 253 | return filter(condition, e -> { 254 | N v = Any.of(e).get(fun); 255 | if (Objects.isNull(v)) { 256 | return false; 257 | } 258 | return v.compareTo(value) >= 0; 259 | }); 260 | } 261 | 262 | /** 263 | * 区间 264 | * 265 | * @param fun 属性 266 | * @param leftValue 左值 267 | * @param rightValue 右值 268 | */ 269 | default > W between(boolean condition, Function fun, N leftValue, N rightValue) { 270 | 271 | if (!condition || EmptyUtil.isAllEmpty(leftValue, rightValue)) { 272 | return filter(true, e -> true); 273 | } 274 | Predicate predicate = e -> true; 275 | if (Objects.nonNull(leftValue)) { 276 | predicate = predicate.and(e -> { 277 | N v = Any.of(e).get(fun); 278 | if (Objects.isNull(v)) { 279 | return false; 280 | } 281 | return v.compareTo(leftValue) >= 0; 282 | }); 283 | } 284 | if (Objects.nonNull(rightValue)) { 285 | predicate = predicate.and(e -> { 286 | N v = Any.of(e).get(fun); 287 | if (Objects.isNull(v)) { 288 | return false; 289 | } 290 | return v.compareTo(rightValue) <= 0; 291 | }); 292 | } 293 | return filter(true, predicate); 294 | } 295 | 296 | /** 297 | * 过滤指定字符属性以value开头的元素 298 | * 299 | * @param fun 属性 300 | * @param value 值 301 | */ 302 | default W rightLike(boolean condition, Function fun, String value) { 303 | return filter(condition, e -> { 304 | String str = Any.of(e).get(fun); 305 | if (Objects.isNull(str)) { 306 | return Objects.isNull(value); 307 | } 308 | if (Objects.isNull(value)) { 309 | return false; 310 | } 311 | return str.startsWith(value); 312 | }); 313 | } 314 | 315 | default W like(boolean condition, Function fun, String value) { 316 | return filter(condition, e -> { 317 | String str = Any.of(e).get(fun); 318 | if (Objects.isNull(str)) { 319 | return Objects.isNull(value); 320 | } 321 | if (Objects.isNull(value)) { 322 | return false; 323 | } 324 | return str.contains(value); 325 | }); 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/Ztream.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream; 2 | 3 | import com.taowater.taol.core.convert.ConvertUtil; 4 | import com.taowater.taol.core.function.Function2; 5 | import com.taowater.taol.core.util.EmptyUtil; 6 | import com.taowater.ztream.assist.BreakException; 7 | import com.taowater.ztream.assist.Functions; 8 | import com.taowater.ztream.assist.Spliterators; 9 | import com.taowater.ztream.op.GroupBy; 10 | import com.taowater.ztream.op.ToMap; 11 | 12 | import java.util.*; 13 | import java.util.concurrent.atomic.AtomicInteger; 14 | import java.util.function.*; 15 | import java.util.stream.IntStream; 16 | import java.util.stream.LongStream; 17 | import java.util.stream.Stream; 18 | import java.util.stream.StreamSupport; 19 | 20 | /** 21 | * 增强流 22 | * 23 | * @author Zhu56 24 | */ 25 | @SuppressWarnings({"unused", "unchecked"}) 26 | public final class Ztream extends AbstractZtream> implements GroupBy, 27 | ToMap { 28 | 29 | Ztream(Stream stream) { 30 | super(stream); 31 | } 32 | 33 | @Override 34 | public Ztream ztream(Stream stream) { 35 | return new Ztream<>(stream); 36 | } 37 | 38 | @Override 39 | public Ztream map(Function mapper) { 40 | return new Ztream<>(stream.map(mapper)); 41 | } 42 | 43 | /** 44 | * 带索引的元素映射 45 | * 46 | * @param mapper 映射器 47 | * @return {@link Ztream}<{@link R}> 48 | */ 49 | public Ztream map(BiFunction mapper) { 50 | return new Ztream<>(stream.map(new Functions.IndexedFunction<>(mapper))); 51 | } 52 | 53 | @Override 54 | public Ztream flatMap(Function> mapper) { 55 | return new Ztream<>(stream.flatMap(mapper)); 56 | } 57 | 58 | /** 59 | * 返回一个空的串行流 60 | * 61 | * @return {@link Ztream}<{@link T}> 62 | */ 63 | public static Ztream empty() { 64 | return new Ztream<>(Stream.empty()); 65 | } 66 | 67 | public static EntryZtream of(Map map) { 68 | return EmptyUtil.isEmpty(map) ? EntryZtream.empty() : EntryZtream.of(map.entrySet()); 69 | } 70 | 71 | /** 72 | * 不定量元素创建流 73 | * 74 | * @param values 若干元素 75 | * @return {@link Ztream}<{@link T}> 76 | */ 77 | @SafeVarargs 78 | @SuppressWarnings("varargs") 79 | public static Ztream of(T... values) { 80 | return EmptyUtil.isEmpty(values) ? empty() : of(Stream.of(values)); 81 | } 82 | 83 | /** 84 | * 由实现{@link Iterable}接口的对象创建非并行流 85 | * 86 | * @param iterable iterable 87 | * @return {@link Ztream}<{@link T}> 88 | */ 89 | public static Ztream of(Iterable iterable) { 90 | return of(iterable, false); 91 | } 92 | 93 | /** 94 | * 由实现{@link Iterable}接口的对象创建流 95 | * 96 | * @param iterable iterable 97 | * @param parallel 是否并行 98 | * @return {@link Ztream}<{@link T}> 99 | */ 100 | public static Ztream of(Iterable iterable, boolean parallel) { 101 | return Any.of(iterable).map(Iterable::spliterator).map(spliterator -> StreamSupport.stream(spliterator, parallel)).map(Ztream::new).orElseGet(Ztream::empty); 102 | } 103 | 104 | /** 105 | * 从标准流创建增强流 106 | * 107 | * @param stream 流 108 | * @return {@link Ztream}<{@link T}> 109 | */ 110 | public static Ztream of(Stream stream) { 111 | return Any.of(stream).map(Ztream::new).orElseGet(Ztream::empty); 112 | } 113 | 114 | 115 | /** 116 | * 分割 117 | * 118 | * @param obj 源对象 119 | */ 120 | public static Ztream split(Object obj) { 121 | return split(obj, ","); 122 | } 123 | 124 | /** 125 | * 分割 126 | * 127 | * @param obj 源对象 128 | * @param delimiter 分隔符 129 | */ 130 | public static Ztream split(Object obj, String delimiter) { 131 | return split(obj, delimiter, String::valueOf); 132 | } 133 | 134 | /** 135 | * 分割 136 | * 137 | * @param obj 源对象 138 | * @param delimiter 分隔符 139 | * @param action 元素转换方法 140 | */ 141 | public static Ztream split(Object obj, String delimiter, Function action) { 142 | return split(obj, delimiter, action, true); 143 | } 144 | 145 | /** 146 | * 分割 147 | * 148 | * @param obj 源对象 149 | * @param delimiter 分隔符 150 | * @param action 元素转换方法 151 | * @param distinct 是否去重 152 | */ 153 | public static Ztream split(Object obj, String delimiter, Function action, boolean distinct) { 154 | String str = Any.of(obj).get(String::valueOf); 155 | if (Objects.isNull(str)) { 156 | return empty(); 157 | } 158 | return Ztream.of(str.split(delimiter)).map(String::trim).map(action).distinct(distinct); 159 | } 160 | 161 | /** 162 | * 遍历 163 | * 164 | * @param action 行动 165 | * @return {@link Ztream}<{@link T}> 166 | */ 167 | public Ztream peek(ObjIntConsumer action) { 168 | return peek(new Functions.IndexedConsumer<>(action)); 169 | } 170 | 171 | /** 172 | * 遍历 173 | * 174 | * @param action 当前元素及遍历下标 175 | */ 176 | public void forEach(ObjIntConsumer action) { 177 | forEach(new Functions.IndexedConsumer<>(action)); 178 | } 179 | 180 | /** 181 | * 转换类型 182 | * 183 | * @param clazz clazz 184 | */ 185 | public Ztream convert(Class clazz) { 186 | return convert(clazz, ConvertUtil::convert, null); 187 | } 188 | 189 | /** 190 | * 转换元素类型 191 | * 192 | * @param clazz 类型 193 | * @param convertFun 转换方法 194 | */ 195 | public Ztream convert(Class clazz, Function2, N> convertFun) { 196 | return convert(clazz, convertFun, null); 197 | } 198 | 199 | /** 200 | * 转换元素类型,按新旧元素入参的消费方法处理元素 201 | * 202 | * @param clazz clazz 203 | * @param consumer 处理函数 204 | */ 205 | public Ztream convert(Class clazz, BiConsumer consumer) { 206 | return convert(clazz, ConvertUtil::convert, consumer); 207 | } 208 | 209 | /** 210 | * 转换 211 | * 212 | * @param clazz 转换类型 213 | * @param convertFun 转换方法 214 | * @param consumer 新旧对象的上下文处理函数 215 | */ 216 | public Ztream convert(Class clazz, Function2, N> convertFun, BiConsumer consumer) { 217 | return map(e -> { 218 | N n = convertFun.apply(e, clazz); 219 | if (Objects.nonNull(consumer)) { 220 | consumer.accept(e, n); 221 | } 222 | return n; 223 | }); 224 | } 225 | 226 | /** 227 | * 追加元素 228 | * 229 | * @param values 值 230 | */ 231 | @SafeVarargs 232 | public final Ztream append(T... values) { 233 | if (EmptyUtil.isEmpty(values)) { 234 | return this; 235 | } 236 | return append(Arrays.spliterator(values)); 237 | } 238 | 239 | /** 240 | * 追加元素 241 | * 242 | * @param iterable iterable 可迭代元素 243 | */ 244 | public Ztream append(Iterable iterable) { 245 | if (Objects.isNull(iterable)) { 246 | return this; 247 | } 248 | return append(iterable.spliterator()); 249 | } 250 | 251 | /** 252 | * 追加元素 253 | * 254 | * @param spliterator 分割器 255 | */ 256 | public Ztream append(Spliterator spliterator) { 257 | if (EmptyUtil.isEmpty(spliterator)) { 258 | return this; 259 | } 260 | Spliterator left = spliterator(); 261 | Spliterator result = (Spliterator) spliterator; 262 | if (left.getExactSizeIfKnown() != 0) { 263 | result = new Spliterators.AppendSpliterator<>(left, spliterator); 264 | } 265 | return Ztream.of(StreamSupport.stream(result, isParallel())); 266 | } 267 | 268 | /** 269 | * 找到符合条件的第一个元素的下标 270 | * 271 | * @param predicate 判断函数 272 | * @return int 下标 273 | */ 274 | public int firstIdx(Predicate predicate) { 275 | AtomicInteger index = new AtomicInteger(-1); 276 | try { 277 | this.forEach((e, i) -> { 278 | if (predicate.test(e)) { 279 | index.set(i); 280 | throw new BreakException(); 281 | } 282 | }); 283 | } catch (BreakException ignore) { 284 | } 285 | return index.get(); 286 | } 287 | 288 | /** 289 | * 收集某个集合类型的属性并展开 290 | * 291 | * @param mapper 属性 292 | */ 293 | public > Ztream flat(Function mapper) { 294 | return this.map(mapper).flatMap(Ztream::of); 295 | } 296 | 297 | /** 298 | * 强转元素类型 299 | * 300 | * @param clazz 目标类型 301 | */ 302 | public Ztream cast(Class clazz) { 303 | return map(clazz::cast); 304 | } 305 | 306 | /** 307 | * 分页 308 | * 309 | * @param no 页码 310 | * @param size 页长 311 | */ 312 | public Ztream page(long no, long size) { 313 | return skip((no - 1) * size).limit(size); 314 | } 315 | 316 | /** 317 | * 数字范围构建流 318 | * 319 | * @param start 开始 320 | * @param end 结束 321 | * 322 | */ 323 | public static Ztream range(int start, int end) { 324 | return Ztream.range(start, end, false); 325 | } 326 | 327 | /** 328 | * 数字范围构建流 329 | * 330 | * @param start 开始 331 | * @param end 结束 332 | * @param closed 是否包含尾数 333 | * 334 | */ 335 | public static Ztream range(int start, int end, boolean closed) { 336 | BiFunction fun = closed ? IntStream::rangeClosed : IntStream::range; 337 | return Ztream.of(fun.apply(start, end).boxed()); 338 | } 339 | 340 | /** 341 | * 数字范围构建流 342 | * 343 | * @param start 开始 344 | * @param end 结束 345 | * 346 | */ 347 | public static Ztream range(long start, long end) { 348 | return Ztream.range(start, end, false); 349 | } 350 | 351 | /** 352 | * 数字范围构建流 353 | * 354 | * @param start 开始 355 | * @param end 结束 356 | * @param closed 是否包含尾数 357 | * 358 | */ 359 | public static Ztream range(long start, long end, boolean closed) { 360 | BiFunction fun = closed ? LongStream::rangeClosed : LongStream::range; 361 | return Ztream.of(fun.apply(start, end).boxed()); 362 | } 363 | } 364 | -------------------------------------------------------------------------------- /src/main/java/com/taowater/ztream/assist/ExCollectors.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream.assist; 2 | 3 | 4 | import com.taowater.taol.core.function.Function1; 5 | import com.taowater.taol.core.util.NumberUtil; 6 | import com.taowater.ztream.Any; 7 | import com.taowater.ztream.Ztream; 8 | import com.taowater.ztream.op.math.Peak; 9 | import com.taowater.ztream.op.sort.Sorter; 10 | import lombok.experimental.UtilityClass; 11 | 12 | import java.math.BigDecimal; 13 | import java.math.RoundingMode; 14 | import java.util.*; 15 | import java.util.function.BiConsumer; 16 | import java.util.function.BinaryOperator; 17 | import java.util.function.Function; 18 | import java.util.function.Supplier; 19 | import java.util.stream.Collector; 20 | 21 | /** 22 | * 自定义收集器 23 | * 24 | * @author Zhu56 25 | */ 26 | @UtilityClass 27 | @SuppressWarnings("unchecked") 28 | public class ExCollectors { 29 | 30 | /** 31 | * 收集器实现 32 | * Collectors.CollectorImpl 不给我用我不会抄一个过来吗 33 | */ 34 | public static class CollectorImpl implements Collector { 35 | private final Supplier supplier; 36 | private final BiConsumer accumulator; 37 | private final BinaryOperator combiner; 38 | private final Function finisher; 39 | private final Set characteristics; 40 | 41 | CollectorImpl(Supplier supplier, 42 | BiConsumer accumulator, 43 | BinaryOperator combiner, 44 | Function finisher, 45 | Set characteristics) { 46 | this.supplier = supplier; 47 | this.accumulator = accumulator; 48 | this.combiner = combiner; 49 | this.finisher = finisher; 50 | this.characteristics = characteristics; 51 | } 52 | 53 | @SuppressWarnings("unchecked") 54 | CollectorImpl(Supplier supplier, 55 | BiConsumer accumulator, 56 | BinaryOperator combiner, 57 | Set characteristics) { 58 | this(supplier, accumulator, combiner, i -> (R) i, characteristics); 59 | } 60 | 61 | @Override 62 | public BiConsumer accumulator() { 63 | return accumulator; 64 | } 65 | 66 | @Override 67 | public Supplier supplier() { 68 | return supplier; 69 | } 70 | 71 | @Override 72 | public BinaryOperator combiner() { 73 | return combiner; 74 | } 75 | 76 | @Override 77 | public Function finisher() { 78 | return finisher; 79 | } 80 | 81 | @Override 82 | public Set characteristics() { 83 | return characteristics; 84 | } 85 | } 86 | 87 | /** 88 | * 平均值收集器 89 | * 90 | * @param fun 属性 91 | * @param nullCount null是否计数 92 | * @return {@link CollectorImpl }<{@link T }, {@link List }<{@link T }>, {@link N }> 93 | */ 94 | public static CollectorImpl, N> avg(Function1 fun, boolean nullCount) { 95 | return new CollectorImpl<>( 96 | ArrayList::new, 97 | List::add, 98 | (l1, l2) -> { 99 | l1.addAll(l2); 100 | return l1; 101 | }, 102 | list -> { 103 | N sum = Ztream.of(list).sum(fun); 104 | long count = nullCount ? Ztream.of(list).count() : Ztream.of(list).nonNull().map(fun).nonNull().count(); 105 | if (Objects.isNull(sum) || count == 0) { 106 | return null; 107 | } 108 | BigDecimal avgValue = NumberUtil.toBigDecimal(sum).divide(BigDecimal.valueOf(count), 4, RoundingMode.HALF_UP); 109 | return NumberUtil.getValue(avgValue, fun); 110 | }, 111 | Collections.emptySet() 112 | ); 113 | } 114 | 115 | /** 116 | * 最值收集器 117 | * 118 | * @param comparator 比较器 119 | * @param nullMin null视为最小 120 | * @return 最值结果 121 | */ 122 | public static CollectorImpl, Peak>> peak(Comparator comparator, boolean nullMin) { 123 | Sorter sorter = new Sorter<>(nullMin); 124 | sorter.asc(comparator, nullMin); 125 | return buildPeak(sorter.getComparator()); 126 | } 127 | 128 | /** 129 | * 最值收集器 130 | * 131 | * @param fun 属性 132 | * @param nullMin null视为最小 133 | * @return 最值结果 134 | */ 135 | public static > CollectorImpl, Peak>> peak(Function1 fun, boolean nullMin) { 136 | Sorter sorter = new Sorter<>(nullMin); 137 | sorter.asc(fun, nullMin); 138 | return buildPeak(sorter.getComparator()); 139 | } 140 | 141 | private static CollectorImpl, Peak>> buildPeak(Comparator finalComparator) { 142 | return new CollectorImpl<>( 143 | Peak::new, 144 | (p, a) -> { 145 | T max = p.getMax(); 146 | T min = p.getMin(); 147 | if (Objects.isNull(max) || finalComparator.compare(max, a) < 0) { 148 | p.setMax(a); 149 | } 150 | if (Objects.isNull(min) || finalComparator.compare(min, a) > 0) { 151 | p.setMin(a); 152 | } 153 | }, 154 | (p1, p2) -> { 155 | T max1 = p1.getMax(); 156 | T min1 = p1.getMin(); 157 | T max2 = p2.getMax(); 158 | T min2 = p2.getMin(); 159 | if (finalComparator.compare(max1, max2) < 0) { 160 | p1.setMax(max2); 161 | } 162 | if (finalComparator.compare(min1, min2) > 0) { 163 | p1.setMin(min2); 164 | } 165 | return p1; 166 | }, 167 | p -> new Peak<>(Any.of(p.getMax()), Any.of(p.getMin())), 168 | Collections.emptySet() 169 | ); 170 | } 171 | 172 | /** 173 | * join 174 | * 175 | * @param delimiter 分隔符 176 | * @return {@link Collector}<{@link T}, {@link ?}, {@link String}> 177 | */ 178 | public static Collector join(CharSequence delimiter) { 179 | return join(delimiter, "", ""); 180 | } 181 | 182 | /** 183 | * join 184 | * 185 | * @param delimiter 分隔符 186 | * @param prefix 前缀 187 | * @param suffix 后缀 188 | * @return {@link Collector}<{@link T}, {@link ?}, {@link String}> 189 | */ 190 | public static Collector join(CharSequence delimiter, 191 | CharSequence prefix, 192 | CharSequence suffix) { 193 | return new CollectorImpl<>( 194 | () -> new StringJoiner(delimiter, prefix, suffix), 195 | (s, t) -> { 196 | if (Objects.nonNull(t)) { 197 | s.add(t.toString()); 198 | } else { 199 | s.add(null); 200 | } 201 | }, 202 | StringJoiner::merge, 203 | StringJoiner::toString, 204 | Collections.emptySet() 205 | ); 206 | } 207 | 208 | /** 209 | * 分组 210 | * 标准流的分组不允许key为null,故改 211 | * 212 | * @return {@link Collector}<{@link T}, {@link ?}, {@link M}> 213 | * @see ExCollectors#groupingBy(Function, Supplier, Collector) 214 | */ 215 | public static > 216 | Collector groupingBy(Function classifier, 217 | Supplier mapFactory, 218 | Collector downstream) { 219 | Supplier downstreamSupplier = downstream.supplier(); 220 | BiConsumer downstreamAccumulator = downstream.accumulator(); 221 | BiConsumer, T> accumulator = (m, t) -> { 222 | K key = null; 223 | if (Objects.nonNull(t)) { 224 | key = classifier.apply(t); 225 | } 226 | A container = m.computeIfAbsent(key, k -> downstreamSupplier.get()); 227 | downstreamAccumulator.accept(container, t); 228 | }; 229 | BinaryOperator> merger = ExCollectors.mapMerger(downstream.combiner()); 230 | @SuppressWarnings("unchecked") 231 | Supplier> mangledFactory = (Supplier>) mapFactory; 232 | 233 | if (downstream.characteristics().contains(Collector.Characteristics.IDENTITY_FINISH)) { 234 | return new CollectorImpl<>(mangledFactory, accumulator, merger, Collections.emptySet()); 235 | } else { 236 | @SuppressWarnings("unchecked") 237 | Function downstreamFinisher = (Function) downstream.finisher(); 238 | Function, M> finisher = intermediate -> { 239 | intermediate.replaceAll((k, v) -> downstreamFinisher.apply(v)); 240 | @SuppressWarnings("unchecked") 241 | M castResult = (M) intermediate; 242 | return castResult; 243 | }; 244 | return new CollectorImpl<>(mangledFactory, accumulator, merger, finisher, Collections.emptySet()); 245 | } 246 | } 247 | 248 | public static 249 | Collector mapping(Function mapper, 250 | Collector downstream) { 251 | BiConsumer downstreamAccumulator = downstream.accumulator(); 252 | return new CollectorImpl<>(downstream.supplier(), 253 | (r, t) -> { 254 | U value = null; 255 | if (Objects.nonNull(t)) { 256 | value = mapper.apply(t); 257 | } 258 | downstreamAccumulator.accept(r, value); 259 | }, 260 | downstream.combiner(), downstream.finisher(), 261 | downstream.characteristics()); 262 | } 263 | 264 | /** 265 | * 合并 266 | * 267 | * @param mergeFunction 合并功能 268 | * @return {@link BinaryOperator}<{@link M}> 269 | */ 270 | private static > 271 | BinaryOperator mapMerger(BinaryOperator mergeFunction) { 272 | return (m1, m2) -> { 273 | for (Map.Entry e : m2.entrySet()) { 274 | m1.merge(e.getKey(), e.getValue(), mergeFunction); 275 | } 276 | return m1; 277 | }; 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /src/test/java/com/taowater/ztream/ZtreamTest.java: -------------------------------------------------------------------------------- 1 | package com.taowater.ztream; 2 | 3 | import com.taowater.taol.core.util.EmptyUtil; 4 | import com.taowater.ztream.TestClass.Student; 5 | import com.taowater.ztream.assist.Functions; 6 | import lombok.SneakyThrows; 7 | import lombok.var; 8 | import org.junit.jupiter.api.Assertions; 9 | import org.junit.jupiter.api.Test; 10 | import org.junit.platform.commons.util.StringUtils; 11 | 12 | import java.text.SimpleDateFormat; 13 | import java.util.*; 14 | import java.util.function.Function; 15 | import java.util.stream.Collectors; 16 | import java.util.stream.Stream; 17 | 18 | import static com.taowater.ztream.TestClass.testList; 19 | 20 | class ZtreamTest { 21 | 22 | @Test 23 | void group() { 24 | Ztream.range(0, 10).forEach(i -> { 25 | }); 26 | var group = Ztream.of(testList).groupBy(Student::getName, Student::getAge, HashMap::new, Collectors.toSet()); 27 | 28 | Map> group2 = new HashMap<>(); 29 | for (var item : testList) { 30 | if (item == null) { 31 | group2.computeIfAbsent(null, k -> new HashSet<>()).add(null); 32 | continue; 33 | } 34 | group2.computeIfAbsent(item.getName(), k -> new HashSet<>()).add(item.getAge()); 35 | } 36 | equals( 37 | group, 38 | group2 39 | ); 40 | 41 | equals( 42 | Ztream.of(testList).group(Student::getName, Student::getAge, Collectors.toSet()), 43 | group2 44 | ); 45 | } 46 | 47 | @Test 48 | void join() { 49 | 50 | equals( 51 | Ztream.of(testList).join(Student::getName), 52 | testList.stream().map(e -> { 53 | if (Objects.isNull(e)) { 54 | return null; 55 | } 56 | return e.getName(); 57 | }).collect(Collectors.joining(",")) 58 | ); 59 | } 60 | 61 | @Test 62 | @SneakyThrows 63 | void nonNull() { 64 | 65 | equals( 66 | Ztream.of(testList).nonNull(), 67 | testList.stream().filter(Objects::nonNull) 68 | ); 69 | 70 | equals( 71 | Ztream.of(testList).nonNull(Student::getName), 72 | testList.stream().filter(e -> Objects.nonNull(e) && Objects.nonNull(e.getName())) 73 | ); 74 | } 75 | 76 | @Test 77 | void distinct() { 78 | List list = newList(1, 4, 5, 9, 3, 2, 3, 4, 5, 6, 7, 8); 79 | 80 | equals( 81 | Ztream.of(list).distinct(), 82 | list.stream().distinct() 83 | ); 84 | 85 | Map map = new LinkedHashMap<>(); 86 | for (Integer i : list) { 87 | map.putIfAbsent(i % 3, i); 88 | } 89 | 90 | equals( 91 | Ztream.of(list).distinct(i -> i % 3), 92 | map.values().stream() 93 | ); 94 | } 95 | 96 | @Test 97 | void hash() { 98 | 99 | Map map = new HashMap<>(); 100 | Map oMap = new HashMap<>(); 101 | for (var item : testList) { 102 | if (item == null) { 103 | if (!map.containsKey(null)) { 104 | map.put(null, null); 105 | } 106 | if (!oMap.containsKey(null)) { 107 | oMap.put(null, null); 108 | } 109 | continue; 110 | } 111 | if (!map.containsKey(item.getName())) { 112 | map.put(item.getName(), item.getAge()); 113 | } 114 | if (!oMap.containsKey(item.getName())) { 115 | oMap.put(item.getName(), item); 116 | } 117 | } 118 | 119 | equals( 120 | Ztream.of(testList).toMap(Student::getName, Student::getAge), 121 | map 122 | ); 123 | 124 | equals( 125 | Ztream.of(testList).toMap(Student::getName), 126 | oMap 127 | ); 128 | 129 | equals( 130 | Ztream.of(testList).hash(Student::getName, Student::getAge), 131 | map 132 | ); 133 | 134 | assert Ztream.of(testList).toMap(Student::getName, () -> new LinkedHashMap<>()) instanceof LinkedHashMap; 135 | 136 | 137 | } 138 | 139 | @Test 140 | void flat() { 141 | List list = newList(1, 2, 4, 6, 4, 8, 9); 142 | Function> fun = e -> newList(1, 2, 3); 143 | equals( 144 | Ztream.of(list).flat(fun), 145 | list.stream().map(fun).flatMap(Collection::stream) 146 | ); 147 | } 148 | 149 | @Test 150 | void sort() { 151 | 152 | equals( 153 | Ztream.of(testList).sort(r -> r 154 | .desc(Student::getName, false) 155 | .asc(false, Student::getAge) 156 | .nullFirst(false) 157 | ), 158 | testList.stream().sorted( 159 | Comparator.nullsLast( 160 | Comparator.comparing(Student::getName, Comparator.nullsLast(Comparator.reverseOrder())) 161 | ) 162 | ) 163 | ); 164 | 165 | equals( 166 | Ztream.of(testList).sort(r -> r 167 | .desc(Student::getName, false) 168 | .asc(Student::getAge) 169 | .nullFirst(false) 170 | ), 171 | testList.stream().sorted( 172 | Comparator.nullsLast( 173 | Comparator.comparing(Student::getName, Comparator.nullsLast(Comparator.reverseOrder())) 174 | .thenComparing(Student::getAge, Comparator.nullsFirst(Comparator.naturalOrder())) 175 | ) 176 | ) 177 | ); 178 | 179 | 180 | equals( 181 | Ztream.of(testList).sort(r -> r 182 | .desc(e -> Objects.nonNull(e.getName())) 183 | .nullFirst(false) 184 | ), 185 | testList.stream().sorted( 186 | Comparator.nullsLast(Comparator.comparing(e -> Objects.nonNull(e.getName()), Comparator.nullsFirst(Comparator.reverseOrder()))) 187 | ) 188 | ); 189 | 190 | equals( 191 | Ztream.of(testList).sort(r -> r 192 | .desc(Student::getName) 193 | .desc(Student::getAge) 194 | ), 195 | testList.stream().sorted( 196 | Comparator.nullsFirst( 197 | Comparator.comparing(Student::getName, Comparator.nullsFirst(Comparator.reverseOrder())) 198 | .thenComparing(Student::getAge, Comparator.nullsFirst(Comparator.reverseOrder())) 199 | ) 200 | )); 201 | } 202 | 203 | @Test 204 | void filter() { 205 | 206 | equals( 207 | Ztream.of(testList).lt(Student::getAge, 5), 208 | testList.stream().filter(e -> Objects.nonNull(e) && Objects.nonNull(e.getAge()) && e.getAge() < 5) 209 | ); 210 | 211 | equals( 212 | Ztream.of(testList).le(Student::getAge, 5), 213 | testList.stream().filter(e -> Objects.nonNull(e) && Objects.nonNull(e.getAge()) && e.getAge() <= 5) 214 | ); 215 | 216 | equals( 217 | Ztream.of(testList).gt(Student::getAge, 7), 218 | testList.stream().filter(e -> Objects.nonNull(e) && Objects.nonNull(e.getAge()) && e.getAge() > 7) 219 | ); 220 | 221 | equals( 222 | Ztream.of(testList).between(Student::getAge, 3, 8), 223 | testList.stream().filter(e -> Objects.nonNull(e) && Objects.nonNull(e.getAge()) && e.getAge() >= 3 && e.getAge() <= 8) 224 | ); 225 | 226 | equals( 227 | Ztream.of(testList).ge(Student::getAge, 3), 228 | testList.stream().filter(e -> Objects.nonNull(e) && Objects.nonNull(e.getAge()) && e.getAge() >= 3) 229 | ); 230 | 231 | equals( 232 | Ztream.of(testList).eq(Student::getName, "小猪"), 233 | testList.stream().filter(e -> Objects.equals("小猪", Any.of(e).get(Student::getName))) 234 | ); 235 | 236 | equals( 237 | Ztream.of(testList).eq(Student::getName, null), 238 | testList.stream().filter(e -> Objects.equals(null, Any.of(e).get(Student::getName))) 239 | ); 240 | 241 | equals( 242 | Ztream.of(testList).isNull(Student::getName), 243 | testList.stream().filter(e -> Objects.equals(null, Any.of(e).get(Student::getName))) 244 | ); 245 | 246 | equals( 247 | Ztream.of(testList).in(Student::getName, "小猪", null), 248 | testList.stream().filter(e -> newList("小猪", null).contains(Any.of(e).get(Student::getName))) 249 | ); 250 | 251 | equals( 252 | Ztream.of(testList).notIn(Student::getName, (String) null, "小猪"), 253 | testList.stream().filter(e -> !newList((String) null, "小猪").contains(Any.of(e).get(Student::getName))) 254 | ); 255 | 256 | equals( 257 | Ztream.of(testList).isNull(), 258 | testList.stream().filter(Objects::isNull) 259 | ); 260 | 261 | equals( 262 | Ztream.of(testList).isBlank(Student::getName), 263 | testList.stream().filter(e -> StringUtils.isBlank(Any.of(e).get(Student::getName))) 264 | ); 265 | 266 | equals( 267 | Ztream.of(testList).nonBlank(Student::getName), 268 | testList.stream().filter(e -> StringUtils.isNotBlank((Any.of(e).get(Student::getName)))) 269 | ); 270 | 271 | equals( 272 | Ztream.of(testList).nonEmpty(Student::getName), 273 | testList.stream().filter(e -> EmptyUtil.isNotEmpty((Any.of(e).get(Student::getName)))) 274 | ); 275 | equals( 276 | Ztream.of(testList).rightLike(Student::getName, "小"), 277 | testList.stream().filter(e -> { 278 | String str = Any.of(e).get(Student::getName); 279 | if (EmptyUtil.isEmpty(str)) { 280 | return false; 281 | } 282 | return str.startsWith("小"); 283 | }) 284 | ); 285 | 286 | Ztream.of(testList).query(w -> w 287 | .eq(Student::getAge, 2) 288 | .in(Student::getName, "2134") 289 | .or(w2 -> w2 290 | .in(Student::getName, "123") 291 | ) 292 | ).toList(); 293 | 294 | equals( 295 | Ztream.of(testList).filter(Objects::isNull), 296 | testList.stream().filter(Objects::isNull) 297 | ); 298 | 299 | equals( 300 | Ztream.of(testList).nonNull().isTrue(TestClass.Person::getFlag), 301 | testList.stream().filter(e -> { 302 | if (e == null) { 303 | return false; 304 | } 305 | Boolean flag = Any.of(e).get(TestClass.Person::getFlag); 306 | if (flag == null) { 307 | return false; 308 | } 309 | return flag; 310 | }) 311 | ); 312 | } 313 | 314 | @Test 315 | void wrapper() { 316 | Ztream.of(testList).query(w -> w 317 | .gt(Student::getAge, 20) 318 | ).forEach(System.out::println); 319 | 320 | 321 | equals( 322 | Ztream.of(testList) 323 | .hash(Student::getName, Student::getAge) 324 | .nonNullKey() 325 | .nonNullValue() 326 | .filterKey(k -> k.startsWith("小")) 327 | .toMap(), 328 | testList.stream() 329 | .filter(e -> !(e == null || e.getName() == null || e.getAge() == null)) 330 | .filter(e -> e.getName().startsWith("小")) 331 | .collect(HashMap::new, (map, item) -> { 332 | String key = item.getName(); 333 | Integer value = item.getAge(); 334 | if (!map.containsKey(key)) { 335 | map.put(key, value); 336 | } 337 | }, 338 | Map::putAll) 339 | ); 340 | 341 | } 342 | 343 | @Test 344 | void peak() { 345 | 346 | var o = Ztream.of(testList).maxBy(Student::getAge).orElse(null); 347 | var o2 = Ztream.of(testList).minBy(Student::getAge, false).orElse(null); 348 | System.out.println(o); 349 | System.out.println(o2); 350 | 351 | var list = newList(null, 1, 2, 3, 4, 5, 6, null); 352 | 353 | equals( 354 | Ztream.of(list).min(false).orElse(null), 355 | 1 356 | ); 357 | 358 | equals( 359 | Ztream.of(list).max().orElse(null), 360 | 6 361 | ); 362 | 363 | var today = new Date(); 364 | var yesterday = new Date(today.getTime() - 1000 * 60 * 24L); 365 | var tomorrow = new Date(today.getTime() + 1000 * 60 * 24L); 366 | 367 | var dates = newList(yesterday, today, tomorrow); 368 | 369 | equals( 370 | Ztream.of(dates).max().get(ZtreamTest::formatDate), 371 | ZtreamTest.formatDate(tomorrow) 372 | ); 373 | 374 | equals( 375 | Ztream.of(dates).min().get(ZtreamTest::formatDate), 376 | ZtreamTest.formatDate(yesterday) 377 | ); 378 | } 379 | 380 | @Test 381 | void math() { 382 | 383 | equals( 384 | Ztream.of(testList).avg(Student::getAge, 0), 385 | (int) (testList.stream().mapToInt(e -> Any.of(e).map(Student::getAge).orElse(0)).average().getAsDouble()) 386 | ); 387 | 388 | equals( 389 | Ztream.of(testList).sum(Student::getAge), 390 | testList.stream().mapToInt(e -> Any.of(e).map(Student::getAge).orElse(0)).sum() 391 | ); 392 | 393 | equals( 394 | Ztream.of(testList).max(Student::getAge), 395 | testList.stream().mapToInt(e -> Any.of(e).map(Student::getAge).orElse(Integer.MIN_VALUE)).max().getAsInt() 396 | ); 397 | 398 | equals( 399 | Ztream.of(testList).nonNull(Student::getAge).min(Student::getAge), 400 | testList.stream().mapToInt(e -> Any.of(e).map(Student::getAge).orElse(Integer.MAX_VALUE)).min().getAsInt() 401 | ); 402 | } 403 | 404 | @Test 405 | void collect() { 406 | equals( 407 | Ztream.of(testList).toList(), 408 | testList 409 | ); 410 | 411 | equals( 412 | Ztream.of(testList).toList(Student::getName), 413 | testList.stream().map(e -> Any.of(e).get(Student::getName)).collect(Collectors.toList()) 414 | ); 415 | equals( 416 | Ztream.of(testList).toList(TestClass.Teacher.class), 417 | testList.stream().map(e -> Any.of(e).get(TestClass.Teacher.class)).collect(Collectors.toList()) 418 | ); 419 | 420 | equals( 421 | Ztream.of(testList).toSet(), 422 | new HashSet<>(testList) 423 | ); 424 | 425 | equals( 426 | Ztream.of(testList).toSet(Student::getName), 427 | testList.stream().map(e -> Any.of(e).get(Student::getName)).collect(Collectors.toSet()) 428 | ); 429 | equals( 430 | Ztream.of(testList).toSet(TestClass.Teacher.class), 431 | testList.stream().map(e -> Any.of(e).get(TestClass.Teacher.class)).collect(Collectors.toSet()) 432 | ); 433 | 434 | 435 | } 436 | 437 | @Test 438 | void append() { 439 | List list = newList(1, 2, 3, 4, 5, 6); 440 | equals( 441 | Ztream.of(list).distinct().append(Ztream.of(7, 8, 9)), 442 | newList(1, 2, 3, 4, 5, 6, 7, 8, 9) 443 | ); 444 | equals( 445 | Ztream.of(list).distinct().append(7, 8, 9), 446 | newList(1, 2, 3, 4, 5, 6, 7, 8, 9) 447 | ); 448 | equals( 449 | Ztream.of(list).append(newSet(7, 8, 8, 9)), 450 | newList(1, 2, 3, 4, 5, 6, 7, 8, 9) 451 | ); 452 | 453 | equals( 454 | Ztream.of(list).append(Ztream.of(7, 8, 9)), 455 | newList(1, 2, 3, 4, 5, 6, 7, 8, 9) 456 | ); 457 | } 458 | 459 | 460 | @Test 461 | void judge() { 462 | Assertions.assertFalse(Ztream.of(testList).hadRepeat()); 463 | Assertions.assertTrue(Ztream.of(testList).hadRepeat(Student::getName)); 464 | Assertions.assertTrue(Ztream.of(testList).anyMatch(Student::getName, Objects::isNull)); 465 | Assertions.assertFalse(Ztream.of(testList).noneMatch(Student::getName, Objects::isNull)); 466 | Assertions.assertFalse(Ztream.of(testList).allMatch(Student::getName, Objects::isNull)); 467 | 468 | 469 | Assertions.assertFalse(Ztream.of(null, null).isEmpty()); 470 | Assertions.assertTrue(Ztream.of(null, null).nonNull().isEmpty()); 471 | Assertions.assertTrue(Ztream.of(null, null).isNotEmpty()); 472 | 473 | Assertions.assertFalse(Ztream.of((Boolean) null, null).allMatch(Functions.of(e -> e))); 474 | 475 | } 476 | 477 | @Test 478 | void shuffle() { 479 | Ztream.of(testList).shuffle().limit(3).nonNull().map(Student::getAge).forEach(System.out::println); 480 | } 481 | 482 | @Test 483 | void query() { 484 | equals( 485 | Ztream.of(testList).last().orElse(null), 486 | testList.get(testList.size() - 1) 487 | ); 488 | } 489 | 490 | @Test 491 | void page() { 492 | equals( 493 | Ztream.of(testList).page(2, 3).toList(), 494 | testList.subList(3, 6) 495 | ); 496 | } 497 | 498 | public static void equals(T o1, T o2) { 499 | Assertions.assertEquals(o1, o2); 500 | } 501 | 502 | public static void equals(Ztream ztream, Stream stream) { 503 | equals(ztream.toList(), stream.collect(Collectors.toList())); 504 | } 505 | 506 | public static void equals(EntryZtream ztream, Map map) { 507 | equals(ztream.toMap(), map); 508 | } 509 | 510 | public static void equals(Ztream ztream, Collection coll) { 511 | equals(ztream.toList(), coll); 512 | } 513 | 514 | public static List newList(T... values) { 515 | List list = new ArrayList<>(); 516 | list.addAll(Arrays.asList(values)); 517 | return list; 518 | } 519 | 520 | public static Set newSet(T... values) { 521 | Set set = new HashSet<>(); 522 | set.addAll(Arrays.asList(values)); 523 | return set; 524 | } 525 | 526 | public static String formatDate(Date date) { 527 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); 528 | return sdf.format(date); 529 | } 530 | } --------------------------------------------------------------------------------

4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | github star 15 | 16 |