001/*
002 *    Copyright 2024-2025, Warm-Flow (290631660@qq.com).
003 *
004 *    Licensed under the Apache License, Version 2.0 (the "License");
005 *    you may not use this file except in compliance with the License.
006 *    You may obtain a copy of the License at
007 *
008 *       https://www.apache.org/licenses/LICENSE-2.0
009 *
010 *    Unless required by applicable law or agreed to in writing, software
011 *    distributed under the License is distributed on an "AS IS" BASIS,
012 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *    See the License for the specific language governing permissions and
014 *    limitations under the License.
015 */
016package org.dromara.warm.flow.core.utils;
017
018
019import java.util.*;
020import java.util.function.BiFunction;
021import java.util.function.Function;
022import java.util.function.IntFunction;
023import java.util.function.Predicate;
024import java.util.stream.Collectors;
025
026/**
027 * stream 流工具类
028 *
029 * @author warm
030 */
031public class StreamUtils {
032
033    private StreamUtils() {
034    }
035
036    /**
037     * 将collection过滤
038     *
039     * @param collection 需要转化的集合
040     * @param function   过滤方法
041     * @return 过滤后的list
042     */
043    public static <E> List<E> filter(Collection<E> collection, Predicate<E> function) {
044        if (CollUtil.isEmpty(collection)) {
045            return new ArrayList<>();
046        }
047        // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
048        return collection.stream().filter(function).collect(Collectors.toList());
049    }
050
051    /**
052     * 将collection拼接
053     *
054     * @param collection 需要转化的集合
055     * @param function   拼接方法
056     * @return 拼接后的list
057     */
058    public static <E> String join(Collection<E> collection, Function<E, String> function) {
059        return join(collection, function, ",");
060    }
061
062    /**
063     * 将collection拼接
064     *
065     * @param collection 需要转化的集合
066     * @param function   拼接方法
067     * @param delimiter  拼接符
068     * @return 拼接后的list
069     */
070    public static <E> String join(Collection<E> collection, Function<E, String> function, CharSequence delimiter) {
071        if (CollUtil.isEmpty(collection)) {
072            return "";
073        }
074        return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter));
075    }
076
077    /**
078     * 将collection排序
079     *
080     * @param collection 需要转化的集合
081     * @param comparing  排序方法
082     * @return 排序后的list
083     */
084    public static <E> List<E> sorted(Collection<E> collection, Comparator<E> comparing) {
085        if (CollUtil.isEmpty(collection)) {
086            return new ArrayList<>();
087        }
088        // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
089        return collection.stream().filter(Objects::nonNull).sorted(comparing).collect(Collectors.toList());
090    }
091
092    /**
093     * 将collection转化为类型不变的map<br>
094     * <B>{@code Collection<V>  ---->  Map<K,V>}</B>
095     *
096     * @param collection 需要转化的集合
097     * @param key        V类型转化为K类型的lambda方法
098     * @param <V>        collection中的泛型
099     * @param <K>        map中的key类型
100     * @return 转化后的map
101     */
102    public static <V, K> Map<K, V> toIdentityMap(Collection<V> collection, Function<V, K> key) {
103        if (CollUtil.isEmpty(collection)) {
104            return new HashMap<>();
105        }
106        return collection.stream().filter(Objects::nonNull)
107                .collect(Collectors.toMap(key, Function.identity(), (l, r) -> l));
108    }
109
110    /**
111     * 将Collection转化为map(value类型与collection的泛型不同)<br>
112     * <B>{@code Collection<E> -----> Map<K,V>  }</B>
113     *
114     * @param collection 需要转化的集合
115     * @param key        E类型转化为K类型的lambda方法
116     * @param value      E类型转化为V类型的lambda方法
117     * @param <E>        collection中的泛型
118     * @param <K>        map中的key类型
119     * @param <V>        map中的value类型
120     * @return 转化后的map
121     */
122    public static <E, K, V> Map<K, V> toMap(Collection<E> collection, Function<E, K> key, Function<E, V> value) {
123        if (CollUtil.isEmpty(collection)) {
124            return new HashMap<>();
125        }
126        return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, value, (l, r) -> l));
127    }
128
129    /**
130     * 将collection按照规则(比如有相同的班级id)分类成map<br>
131     * <B>{@code Collection<E> -------> Map<K,List<E>> } </B>
132     *
133     * @param collection 需要分类的集合
134     * @param key        分类的规则
135     * @param <E>        collection中的泛型
136     * @param <K>        map中的key类型
137     * @return 分类后的map
138     */
139    public static <E, K> Map<K, List<E>> groupByKey(Collection<E> collection, Function<E, K> key) {
140        if (CollUtil.isEmpty(collection)) {
141            return new HashMap<>();
142        }
143        return collection.stream().filter(Objects::nonNull)
144                .collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList()));
145    }
146
147    /**
148     * 将collection按照规则(比如有相同的班级id)分类成map<br>
149     * <B>{@code Collection<E> -------> Map<K,List<E>> } </B>
150     *
151     * @param collection 需要分类的集合
152     * @param key        分类的规则
153     * @param <E>        collection中的泛型
154     * @param <K>        map中的key类型
155     * @return 分类后的map
156     */
157    public static <T, E, K> Map<K, List<E>> groupByKeyFilter(Predicate<E> predicate, Collection<E> collection, Function<E, K> key) {
158        if (CollUtil.isEmpty(collection)) {
159            return new HashMap<>();
160        }
161        return collection.stream().filter(predicate)
162                .collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList()));
163    }
164
165    /**
166     * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map<br>
167     * <B>{@code Collection<E>  --->  Map<T,Map<U,List<E>>> } </B>
168     *
169     * @param collection 需要分类的集合
170     * @param key1       第一个分类的规则
171     * @param key2       第二个分类的规则
172     * @param <E>        集合元素类型
173     * @param <K>        第一个map中的key类型
174     * @param <U>        第二个map中的key类型
175     * @return 分类后的map
176     */
177    public static <E, K, U> Map<K, Map<U, List<E>>> groupBy2Key(Collection<E> collection, Function<E, K> key1,
178                                                                Function<E, U> key2) {
179        if (CollUtil.isEmpty(collection)) {
180            return new HashMap<>();
181        }
182        return collection.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(key1, LinkedHashMap::new,
183                Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList())));
184    }
185
186    /**
187     * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map<br>
188     * <B>{@code Collection<E>  --->  Map<T,Map<U,E>> } </B>
189     *
190     * @param collection 需要分类的集合
191     * @param key1       第一个分类的规则
192     * @param key2       第二个分类的规则
193     * @param <T>        第一个map中的key类型
194     * @param <U>        第二个map中的key类型
195     * @param <E>        collection中的泛型
196     * @return 分类后的map
197     */
198    public static <E, T, U> Map<T, Map<U, E>> group2Map(Collection<E> collection, Function<E, T> key1,
199                                                        Function<E, U> key2) {
200        if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) {
201            return new HashMap<>();
202        }
203        return collection.stream().filter(Objects::nonNull).collect(
204                Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l)));
205    }
206
207    /**
208     * 将collection转化为List集合,但是两者的泛型不同<br>
209     * <B>{@code Collection<E>  ------>  List<T> } </B>
210     *
211     * @param collection 需要转化的集合
212     * @param function   collection中的泛型转化为list泛型的lambda表达式
213     * @param <E>        collection中的泛型
214     * @param <T>        List中的泛型
215     * @return 转化后的list
216     */
217    public static <E, T> List<T> toList(Collection<E> collection, Function<E, T> function) {
218        if (CollUtil.isEmpty(collection)) {
219            return new ArrayList<>();
220        }
221        return collection.stream().map(function).filter(Objects::nonNull)
222                // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
223                .collect(Collectors.toList());
224    }
225
226    /**
227     * 将collection转化为Set集合,但是两者的泛型不同<br>
228     * <B>{@code Collection<E>  ------>  Set<T> } </B>
229     *
230     * @param collection 需要转化的集合
231     * @param function   collection中的泛型转化为set泛型的lambda表达式
232     * @param <E>        collection中的泛型
233     * @param <T>        Set中的泛型
234     * @return 转化后的Set
235     */
236    public static <E, T> Set<T> toSet(Collection<E> collection, Function<E, T> function) {
237        if (CollUtil.isEmpty(collection) || function == null) {
238            return new HashSet<>();
239        }
240        return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.toSet());
241    }
242
243    /**
244     * 将collection转化为List集合,但是两者的泛型不同<br>
245     * <B>{@code Collection<E>  ------>  List<T> } </B>
246     *
247     * @param collection 需要转化的集合
248     * @param generator  collection中的泛型转化为list泛型的lambda表达式
249     * @param <E>        collection中的泛型
250     * @return 转化后的list
251     */
252    public static <E> E[] toArray(Collection<E> collection, IntFunction<E[]> generator) {
253        if (CollUtil.isEmpty(collection)) {
254            return generator.apply(0);
255        }
256        return collection.stream().toArray(generator);
257    }
258
259    /**
260     * 合并两个相同key类型的map
261     *
262     * @param map1  第一个需要合并的 map
263     * @param map2  第二个需要合并的 map
264     * @param merge 合并的lambda,将key value1 value2合并成最终的类型,注意value可能为空的情况
265     * @param <K>   map中的key类型
266     * @param <X>   第一个 map的value类型
267     * @param <Y>   第二个 map的value类型
268     * @param <V>   最终map的value类型
269     * @return 合并后的map
270     */
271    public static <K, X, Y, V> Map<K, V> merge(Map<K, X> map1, Map<K, Y> map2, BiFunction<X, Y, V> merge) {
272        if (MapUtil.isEmpty(map1) && MapUtil.isEmpty(map2)) {
273            return new HashMap<>();
274        } else if (MapUtil.isEmpty(map1)) {
275            map1 = new HashMap<>();
276        } else if (MapUtil.isEmpty(map2)) {
277            map2 = new HashMap<>();
278        }
279        Set<K> key = new HashSet<>();
280        key.addAll(map1.keySet());
281        key.addAll(map2.keySet());
282        Map<K, V> map = new HashMap<>();
283        for (K t : key) {
284            X x = map1.get(t);
285            Y y = map2.get(t);
286            V z = merge.apply(x, y);
287            if (z != null) {
288                map.put(t, z);
289            }
290        }
291        return map;
292    }
293
294}