java两个对象List根据多个对象属性取交集和差集

413 阅读1分钟
有时候需要对前端传入的参数集合和数据库查询出来的集合数据根据对象属性进行对比判断是新增,更新,删除这些数据。
  • newList 和 existList 的交集 就是 更新的数据
  • newList - existList 的差集 就是 新增的数据
  • existList - newList 的差集 就是 删除的数据

1.新创建一个实体类

import lombok.Data;

/**
 * @Author yang
 **/
@Data
public class Person {

    public Person(String name, int age, String occupation) {
        this.name = name;
        this.age = age;
        this.occupation = occupation;
    }
    private String name;
    private int age;
    private String occupation;
}

2.集合的交集,差集工具类

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author yang
 **/
public class CollectUtils {

    private CollectUtils() {

    }

    /**
     * 集合的交集
     * @param existList
     * @param newList
     * @param attributeNames
     * @return
     * @param <T>
     */
    public static <T> List<T> intersectionByAttributes(List<T> existList, List<T> newList, String... attributeNames) {
        return existList.stream()
                .filter(obj1 -> newList.stream()
                        .anyMatch(obj2 -> matchAttributes(obj1, obj2, attributeNames)))
                .collect(Collectors.toList());
    }

    /**
     * 集合的差集
     * @param existList
     * @param newList
     * @param attributeNames
     * @return
     * @param <T>
     */
    public static <T> List<T> differenceByAttributes(List<T> existList, List<T> newList, String... attributeNames) {
        Set<List<Object>> attributesSet = existList.stream()
                .map(obj2 -> getAttributeValues(obj2, attributeNames))
                .collect(Collectors.toSet());
        return newList.stream()
                .filter(obj1 -> !attributesSet.contains(getAttributeValues(obj1, attributeNames)))
                .collect(Collectors.toList());
    }

    /**
     * 匹配属性
     * @param obj1
     * @param obj2
     * @param attributeNames
     * @return
     * @param <T>
     */
    private static <T> boolean matchAttributes(T obj1, T obj2, String... attributeNames) {
        return Arrays.stream(attributeNames).allMatch(attributeName ->
                Objects.equals(getAttributeValue(obj1, attributeName), getAttributeValue(obj2, attributeName)));
    }

    /**
     * 获取对象中的属性
     * @param obj
     * @param attributeNames
     * @return
     * @param <T>
     */
    private static <T> List<Object> getAttributeValues(T obj, String... attributeNames) {
        return Stream.of(attributeNames)
                .map(attributeName -> getAttributeValue(obj, attributeName))
                .collect(Collectors.toList());
    }

    /**
     *  获取指定的属性值
     * @param obj
     * @param attributeName
     * @return
     * @param <T>
     */
    private static <T> Object getAttributeValue(T obj, String attributeName) {
        Objects.requireNonNull(obj, "Object cannot be null");
        Objects.requireNonNull(attributeName, "Attribute name cannot be null");
        try {
            Field field = obj.getClass().getDeclaredField(attributeName);
            field.setAccessible(true);
            return field.get(obj);
        } catch (ReflectiveOperationException e) {
            throw new IllegalStateException("error accessing attribute ".concat(attributeName), e);
        }
    }


}

3.代码测试

public static void main(String[] args) {
    List<Person> list1 = Lists.newArrayList(
            new Person("John", 25, "Developer"),
            new Person("Jane", 30, "Manager"),
            new Person("Bob", 22, "Intern"));
        
    List<Person> list2 = Lists.newArrayList(
            new Person("Jane", 30, "Manager"),
            new Person(null, 22, "Intern"),
            new Person("Alice", 28, "Engineer"));

    List<Person> intersection = CollectUtils.intersectionByAttributes(list1, list2, "name", "age");
    System.out.println("Intersection by name and age: " + intersection);
    List<Person> difference = CollectUtils.differenceByAttributes(list1, list2, "name", "age");
    System.out.println("difference by name and age: " + difference);
}