支持操作:
- 根据指定字段,获取两个对象集合的交集、补集、并集等
- 将对象中的多个字段值,抽取到一个List中
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* Description:List工具类。用于处理两个列表的交集、并集、差集等操作。
*
* @author jiangniao
* @date 2024-3-22
*/
public class ListUtil {
private ListUtil() {
}
/**
* 提取多个字段的值到一个list
*
* @param list 对象集合
* @param fieldName 需要提取的字段名
* @return
*/
public static List<String> extractFieldsToList(List<?> list, String... fieldName) {
return list.stream().flatMap(item->Arrays.stream(fieldName).map(field->BeanUtils.getSimpleProperty(item, field))).collect(Collectors.toList());
}
/**
* 根据指定字段找出两个列表的交集。
*
* @param list1
* @param list2
* @param fields
* @param <T>
* @return
*/
public static <T> List<T> intersection(List<T> list1, List<T> list2, String... fields) {
return list1.stream().filter(item1->containsWithFields(list2, item1, fields)).collect(Collectors.toList());
}
/**
* 根据指定字段找出两个列表的并集
*
* @param list1
* @param list2
* @param fields
* @param <T>
* @return
*/
public static <T> List<T> union(List<T> list1, List<T> list2, String... fields) {
List<T> union = new ArrayList<>(list1);
union.addAll(list2.stream().filter(item->!containsWithFields(list1, item, fields)).collect(Collectors.toList()));
return union;
}
/**
* 根据指定字段找出两个列表的差集。list1中有,list2中没有的元素
*
* @param list1
* @param list2
* @param fields
* @param <T>
* @return 返回list1过滤后的数据
*/
public static <T> List<T> difference(List<T> list1, List<T> list2, String... fields) {
return list1.stream().filter(item->!containsWithFields(list2, item, fields)).collect(Collectors.toList());
}
/**
* 找出两个列表的差集。list1中有,list2中没有的元素。
* <p>用于非Object对象的比较,比如String、Integer等
*
* @param list1
* @param list2
* @param <T>
* @return 返回list1过滤后的数据
*/
public static <T> List<T> difference(List<T> list1, List<T> list2) {
list1.removeAll(list2);
return list1;
}
/**
* 辅助方法,判断列表中是否包含指定对象
*
* @param list
* @param item
* @param fields
* @param <T>
* @return
*/
private static <T> boolean containsWithFields(List<T> list, T item, String... fields) {
return list.stream().anyMatch(item2->matchesFields(item, item2, fields));
}
/**
* 辅助方法,判断两个对象的指定字段是否相等
*
* @param item1
* @param item2
* @param fields
* @param <T>
* @return
*/
private static <T> boolean matchesFields(T item1, T item2, String... fields) {
try {
for (String field : fields) {
Field declaredField1 = item1.getClass().getDeclaredField(field);
Field declaredField2 = item2.getClass().getDeclaredField(field);
declaredField1.setAccessible(true);
declaredField2.setAccessible(true);
if (!Objects.equals(declaredField1.get(item1), declaredField2.get(item2))) {
return false;
}
}
return true;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 根据指定字段对列表进行去重
*
* @param list
* @param fields
* @param <T>
* @return
*/
public static <T> List<T> distinctByFields(List<T> list, String... fields) {
return list.stream().filter(distinctByKey(t->getKey(t, fields))).collect(Collectors.toList());
}
/**
* 辅助方法,用于生成去重的键
*
* @param keyExtractor
* @param <T>
* @return
*/
private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Map<Object, Boolean> seen = new ConcurrentHashMap<>();
return t->seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
/**
* 辅助方法,生成由指定字段的值组成的键
*
* @param item
* @param fields
* @param <T>
* @return
*/
private static <T> String getKey(T item, String... fields) {
StringBuilder key = new StringBuilder();
try {
for (String field : fields) {
Field declaredField = item.getClass().getDeclaredField(field);
declaredField.setAccessible(true);
key.append(declaredField.get(item)).append("-");
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return key.toString();
}
}