mirror of
https://gitee.com/dromara/hutool.git
synced 2025-04-30 12:47:58 +08:00
commit
5dfd34de3f
175
hutool-core/src/main/java/cn/hutool/core/util/StreamUtil.java
Normal file
175
hutool-core/src/main/java/cn/hutool/core/util/StreamUtil.java
Normal file
@ -0,0 +1,175 @@
|
||||
package cn.hutool.core.util;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.BinaryOperator;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* java Stream工具类
|
||||
* <pre>
|
||||
* 在实际项目中,我们经常需要处理集合对象, 提取集合元素的某个字段集合。
|
||||
* 此工具类可以简化一些代码, 如
|
||||
* 原来需要提取User对象的id集合:
|
||||
* 1 - 写一个for循环
|
||||
* {@code
|
||||
* List<Long> userIds = new ArrayList<>();
|
||||
* for(User user : userList) {
|
||||
* userIds.add(user.getId());
|
||||
* }
|
||||
* }
|
||||
* 2 - 使用java8 引入的stream方式
|
||||
* {@code List<Long> userIds = userList.stream().map(User::getId).collect(Collectors.toList());}
|
||||
*
|
||||
* 3 - 此工具类提供了更简洁的stream写法(无需每次都写{@code collect(Collectors.toList())})
|
||||
* {@code List<Long> userId = StreamUtil.list(userList, User::getId);}
|
||||
* </pre>
|
||||
*
|
||||
* @author yiming
|
||||
*/
|
||||
public class StreamUtil {
|
||||
|
||||
/**
|
||||
* 将指定List元素的某个field提取成新的List(过滤null元素)
|
||||
*
|
||||
* @param sourceList 原list
|
||||
* @param mapperFunction 映射方法
|
||||
* @return 转化后的list
|
||||
*/
|
||||
public static <T, R> List<R> list(List<T> sourceList, Function<T, R> mapperFunction) {
|
||||
if (CollUtil.isEmpty(sourceList)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Assert.notNull(mapperFunction);
|
||||
return sourceList.stream().map(mapperFunction).filter(Objects::nonNull).distinct().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象列表的某个字段list
|
||||
*
|
||||
* @param sourceList 源数据
|
||||
* @param mapperFunction 映射方法
|
||||
* @param filter 过滤器
|
||||
* @param <T> 源数据类型
|
||||
* @param <R> 结果数据类型
|
||||
* @return 转化后的列表数据
|
||||
*/
|
||||
public static <T, R> List<R> list(List<T> sourceList, Function<T, R> mapperFunction, Predicate<? super T> filter) {
|
||||
if (CollUtil.isEmpty(sourceList)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Assert.notNull(mapperFunction);
|
||||
Assert.notNull(filter);
|
||||
return sourceList.stream().filter(filter).map(mapperFunction).distinct().collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定List元素的某个field提取成新的Set(过滤null元素)
|
||||
*
|
||||
* @param sourceList 原list
|
||||
* @param mapperFunction 映射方法
|
||||
* @return 转化后的set
|
||||
*/
|
||||
public static <T, R> Set<R> toSet(List<T> sourceList, Function<T, R> mapperFunction) {
|
||||
return new HashSet<>(list(sourceList, mapperFunction));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定List元素的某个field提取成新的Set(过滤null元素)
|
||||
*
|
||||
* @param sourceList 原list
|
||||
* @param mapperFunction 映射方法
|
||||
* @param filter 过滤器
|
||||
* @return 转化后的set
|
||||
*/
|
||||
public static <T, R> Set<R> toSet(List<T> sourceList, Function<T, R> mapperFunction, Predicate<T> filter) {
|
||||
return new HashSet<>(list(sourceList, mapperFunction, filter));
|
||||
}
|
||||
|
||||
/**
|
||||
* list 转 map
|
||||
*
|
||||
* @param sourceList 源数据
|
||||
* @param keyMapper key映射
|
||||
* @param valueMapper value映射
|
||||
* @param mergeFunction value合并策略
|
||||
* @param <T> 对象集合类型
|
||||
* @param <K> map键类型
|
||||
* @param <R> map值类型
|
||||
* @return 由list转化而的map
|
||||
*/
|
||||
public static <T, K, R> Map<K, R> toMap(List<T> sourceList, Function<T, K> keyMapper, Function<T, R> valueMapper,
|
||||
BinaryOperator<R> mergeFunction) {
|
||||
if (CollUtil.isEmpty(sourceList) || keyMapper == null || valueMapper == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return sourceList.stream().collect(Collectors.toMap(keyMapper, valueMapper, mergeFunction));
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取list指定字段转成map
|
||||
*
|
||||
* @param sourceList 原list
|
||||
* @param keyMapper key映射方法
|
||||
* @param valueMapper value映射方法
|
||||
* @return 指定map
|
||||
*/
|
||||
public static <T, K, R> Map<K, R> toMap(List<T> sourceList, Function<T, K> keyMapper, Function<T, R> valueMapper) {
|
||||
if (CollUtil.isEmpty(sourceList) || keyMapper == null || valueMapper == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return sourceList.stream().collect(Collectors.toMap(keyMapper, valueMapper, (v1, v2) -> v1));
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取list指定字段转成map
|
||||
*
|
||||
* @param sourceList 原list
|
||||
* @param keyMapper key映射方法
|
||||
* @param valueMapper value映射方法
|
||||
* @param filter 过滤器
|
||||
* @return 指定map
|
||||
*/
|
||||
public static <T, K, R> Map<K, R> toMap(List<T> sourceList, Function<T, K> keyMapper, Function<T, R> valueMapper,
|
||||
Predicate<? super T> filter) {
|
||||
if (CollUtil.isEmpty(sourceList) || keyMapper == null || valueMapper == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return sourceList.stream().filter(filter).collect(Collectors.toMap(keyMapper, valueMapper, (v1, v2) -> v1));
|
||||
}
|
||||
|
||||
/**
|
||||
* list -> map (map值类型同list元素类型)
|
||||
*
|
||||
* @param sourceList 源数据
|
||||
* @param keyMapper key映射
|
||||
* @param <T> 对象集合类型
|
||||
* @param <K> map键类型
|
||||
* @return 由list转化而来的map
|
||||
*/
|
||||
public static <T, K> Map<K, T> toMap(List<T> sourceList, Function<T, K> keyMapper) {
|
||||
return toMap(sourceList, keyMapper, Function.identity(), (v1, v2) -> v1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按指定字段分组
|
||||
*
|
||||
* @param sourceList 原list
|
||||
* @param keyMapper 字段映射
|
||||
* @return 分组
|
||||
*/
|
||||
public static <T, K> Map<K, List<T>> groupingBy(List<T> sourceList, Function<T, K> keyMapper) {
|
||||
if (CollUtil.isEmpty(sourceList) || keyMapper == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
return sourceList.stream().collect(Collectors.groupingBy(keyMapper));
|
||||
}
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
package cn.hutool.core.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author yiming
|
||||
* @date 2020/9/4 13:40
|
||||
*/
|
||||
public class StreamUtilTest {
|
||||
|
||||
static List<User> userList = Arrays.asList(
|
||||
new User(1L, "A", 3, true, true, true),
|
||||
new User(2L, "B", 4, true, true, false),
|
||||
new User(3L, "C", 5, true, false, true),
|
||||
new User(4L, "E", 6, true, false, false),
|
||||
new User(5L, "D", 7, false, true, true),
|
||||
new User(6L, "F", 7, false, false, true),
|
||||
new User(7L, "G", 8, false, true, false),
|
||||
new User(8L, "H", 8, false, false, false)
|
||||
);
|
||||
|
||||
@Test
|
||||
public void testList() {
|
||||
List<Long> userIds = StreamUtil.list(userList, User::getId);
|
||||
Assert.assertEquals(userIds.size(), userList.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListFilter() {
|
||||
// 提取管理员用户名称
|
||||
List<String> names = StreamUtil.list(userList, User::getName, x -> Boolean.TRUE.equals(x.isAdmin));
|
||||
Assert.assertEquals(names.size(), 4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToSet() {
|
||||
Set<Integer> ages = StreamUtil.toSet(userList, User::getAge);
|
||||
Assert.assertEquals(ages.size(), 6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToSetFilter() {
|
||||
// 提取大于6的元素
|
||||
Set<Integer> ages = StreamUtil.toSet(userList, User::getAge, x -> x.getAge() > 6);
|
||||
Assert.assertEquals(ages.size(), 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToMap() {
|
||||
Map<Long, User> userMap = StreamUtil.toMap(userList, User::getId);
|
||||
Assert.assertEquals(userMap.size(), userList.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToMapValue() {
|
||||
Map<Long, String> userNameMap = StreamUtil.toMap(userList, User::getId, User::getName);
|
||||
Assert.assertEquals(userNameMap.size(), userList.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToMapFilter() {
|
||||
// 提取年龄>5的用户姓名map
|
||||
Map<Long, String> userNameMap = StreamUtil.toMap(userList, User::getId, User::getName, x -> x.getAge() > 5);
|
||||
Assert.assertEquals(userNameMap.size(), 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToMapMerge() {
|
||||
// 提取用户姓名map - 自定义map的value覆盖策略
|
||||
User tempUser1 = new User(10L, "X", 10, true, false, false);
|
||||
User tempUser2 = new User(10L, "Y", 10, true, false, false);
|
||||
List<User> users = new ArrayList<>();
|
||||
users.add(tempUser1);
|
||||
users.add(tempUser2);
|
||||
// 若新的value同原value,取原value
|
||||
Map<Long, String> userNameMap = StreamUtil.toMap(users, User::getId, User::getName, (v1, v2) -> v1);
|
||||
Assert.assertEquals(userNameMap.get(10L), "X");
|
||||
// 若新的value同原value,取新value
|
||||
userNameMap = StreamUtil.toMap(users, User::getId, User::getName, (v1, v2) -> v2);
|
||||
Assert.assertEquals(userNameMap.get(10L), "Y");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void groupingBy() {
|
||||
// 按年龄分组
|
||||
Map<Integer, List<User>> ageGroupMap = StreamUtil.groupingBy(userList, User::getAge);
|
||||
Assert.assertEquals(ageGroupMap.size(), 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试bean
|
||||
*/
|
||||
public static class User {
|
||||
|
||||
private Long id;
|
||||
private String name;
|
||||
private int age;
|
||||
private boolean isAdmin;
|
||||
private boolean isSuper;
|
||||
private boolean gender;
|
||||
|
||||
public User() {
|
||||
}
|
||||
|
||||
public User(Long id, String name, int age, boolean isAdmin, boolean isSuper, boolean gender) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
this.isAdmin = isAdmin;
|
||||
this.isSuper = isSuper;
|
||||
this.gender = gender;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getAge() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public User setAge(int age) {
|
||||
this.age = age;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String testMethod() {
|
||||
return "test for " + this.name;
|
||||
}
|
||||
|
||||
public boolean isAdmin() {
|
||||
return isAdmin;
|
||||
}
|
||||
|
||||
public void setAdmin(boolean isAdmin) {
|
||||
this.isAdmin = isAdmin;
|
||||
}
|
||||
|
||||
public boolean isIsSuper() {
|
||||
return isSuper;
|
||||
}
|
||||
|
||||
public void setIsSuper(boolean isSuper) {
|
||||
this.isSuper = isSuper;
|
||||
}
|
||||
|
||||
public boolean isGender() {
|
||||
return gender;
|
||||
}
|
||||
|
||||
public void setGender(boolean gender) {
|
||||
this.gender = gender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User [name=" + name + ", age=" + age + ", isAdmin=" + isAdmin + ", gender=" + gender + "]";
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user