比较两个实体类属性值不同的提取出来字段名字段值

package com.alibaba.thead.util;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: zhengpengp
 * @Date: 2021/12/15 14:10
 * @Description: 比较实体属性值是否一致
 */
public class ClassCompareUtil {
    /**
     * 比较两个实体属性值,返回一个boolean,true则表时两个对象中的属性值无差异
     *
     * @param oldObject 进行属性比较的对象1
     * @param newObject 进行属性比较的对象2
     * @return 属性差异比较结果boolean
     */
    public static boolean compareObject(Object oldObject, Object newObject) {
        Map<String, Map<String, Object>> resultMap = compareFields(oldObject, newObject);

        if (resultMap.size() > 0) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 比较两个实体属性值,返回一个map以有差异的属性名为key,value为一个Map分别存oldObject,newObject此属性名的值
     *
     * @param oldObject 进行属性比较的对象1
     * @param newObject 进行属性比较的对象2
     * @return 属性差异比较结果map
     */
    @SuppressWarnings("rawtypes")
    public static Map<String, Map<String, Object>> compareFields(Object oldObject, Object newObject) {
        Map<String, Map<String, Object>> map = null;

        try {
            /**
             * 只有两个对象都是同一类型的才有可比性
             */
            if (oldObject.getClass() == newObject.getClass()) {
                map = new HashMap<String, Map<String, Object>>();

                Class clazz = oldObject.getClass();
                //获取object的所有属性
                PropertyDescriptor[] pds = Introspector.getBeanInfo(clazz, Object.class).getPropertyDescriptors();

                for (PropertyDescriptor pd : pds) {
                    //遍历获取属性名
                    String name = pd.getName();

                    //获取属性的get方法
                    Method readMethod = pd.getReadMethod();

                    // 在oldObject上调用get方法等同于获得oldObject的属性值
                    Object oldValue = readMethod.invoke(oldObject);
                    // 在newObject上调用get方法等同于获得newObject的属性值
                    Object newValue = readMethod.invoke(newObject);

                    if (oldValue instanceof List) {
                        continue;
                    }

                    if (newValue instanceof List) {
                        continue;
                    }

                    if (oldValue instanceof Timestamp) {
                        oldValue = new Date(((Timestamp) oldValue).getTime());
                    }

                    if (newValue instanceof Timestamp) {
                        newValue = new Date(((Timestamp) newValue).getTime());
                    }

                    if (oldValue == null && newValue == null) {
                        continue;
                    } else if (oldValue == null && newValue != null) {
                        Map<String, Object> valueMap = new HashMap<String, Object>();
                        valueMap.put("oldValue", oldValue);
                        valueMap.put("newValue", newValue);

                        map.put(name, valueMap);

                        continue;
                    }

                    if (!oldValue.equals(newValue)) {// 比较这两个值是否相等,不等就可以放入map了
                        Map<String, Object> valueMap = new HashMap<String, Object>();
                        valueMap.put("oldValue", oldValue);
                        valueMap.put("newValue", newValue);

                        map.put(name, valueMap);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return map;
    }
}

<think>首先,用户的问题是:“我想从列表中提取多个属性的组合唯一 请问如何从 List 中提取多个属性的组合唯一”。这涉及到Java中处理List集合的问题。 我需要参考系统级指令: - 所有行内数学表达式用$...$格式。 - 独立公式用$$...$$格式。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾添加引用标识。 - 回答结构清晰,帮助用户逐步解决问题。 用户提供的引用: - 引用[1]:关于Java中List元素排序,使用Collections来排序。 - 引用[2]:关于Java类的合并,合并两个实体类属性值。 用户的问题是从List中提取多个属性的组合唯一。意思是,有一个List的对象,每个对象有多个属性,我需要提取这些属性的组合,并确保唯一性。例如,List<Person>,Person有nameage属性,我想提取所有唯一的(name, age)对。 在Java中,这可以通过使用Set来实现唯一性。Set自动处理唯一性,但需要对象实现equalshashCode方法,或者使用自定义比较器。 步骤: 1. 定义一个类或使用现有类来表示组合属性。 2. 覆盖equalshashCode方法,以便基于这些属性进行比较。 3. 使用Set来存储组合。 或者,使用Java Stream API来简化操作。 参考用户提供的引用: - 引用[1]提到使用Collections排序,但这里不是排序,而是提取唯一组合。 - 引用[2]提到合并实体类属性值,这有点相关,但更侧重于合并而不是提取唯一。 所以,我应该基于问题本身来回答,而不是强加引用。 回答结构: - 解释问题。 - 提供解决方案步骤。 - 给出代码示例。 - 确保代码正确。 - 生成相关问题。 - 添加引用标识(如果有引用)。 代码示例需要用中文注释,并在必要时解释。 解决方案: 1. 使用Java Stream API的distinct()方法,但distinct()依赖于对象的equals方法,所以需要确保对象正确实现equalshashCode。 2. 或者,创建一个新的类来表示组合键,并实现equalshashCode。 3. 使用Map来存储组合键。 例如: - 定义一个record(Java 14+)或一个POJO来表示组合属性。 - 然后使用Stream的mapcollect(Collectors.toSet())来提取唯一。 代码示例: ```java import java.util.*; import java.util.stream.Collectors; public class UniqueAttributes { public static void main(String[] args) { // 示例类 class Person { String name; int age; Person(String name, int age) { this.name = name; this.age = age; } } List<Person> persons = Arrays.asList( new Person("Alice", 30), new Person("Bob", 25), new Person("Alice", 30), // 重复 new Person("Charlie", 25) ); // 提取唯一组合:使用记录(record)或自定义类 // 方法1:使用record(Java 14+) record PersonKey(String name, int age) {} Set<PersonKey> uniqueKeys = persons.stream() .map(p -> new PersonKey(p.name, p.age)) .collect(Collectors.toSet()); System.out.println(uniqueKeys); } } ``` 如果不能用record,可以定义一个内部类。 在Java 8+,可以使用Tuple或Pair类,但Java标准库没有提供,所以最好自定义一个。 或者,使用Map的keySet,但需要处理。 另一个方法:使用Collectors.groupingBy,但那是分组,不是直接提取唯一。 最简单的是用Stream自定义键。 生成相关问题: 基于系统指令,我需要生成相关问题。例如: 1. 如何确保自定义类的equalshashCode正确实现? 2. 如果属性很多,如何动态提取组合唯一? 3. 如何将提取的唯一转换回List? 确保回答真实可靠。 最后,添加引用标识。用户提供了引用,但在这个上下文中,引用[1]是关于排序的,引用[2]是关于合并的,可能不直接相关。我应该自然地引用它们,如果适用。 在回答中,可以说:类似地,在提取唯一时,我们可以借鉴集合操作的思想[^1]。 但不要强行插入。 回答结构: - 开头解释问题。 - 步骤说明。 - 代码示例。 - 相关问题。</think>### 从 List 中提取多个属性的组合唯一Java 中,从 List 集合中提取多个属性的组合唯一,可以通过以下步骤实现: 1. **定义组合键类**:创建一个新类来表示属性的组合,并覆盖 `equals()` `hashCode()` 方法,确保基于多个属性判断唯一性。 2. **使用 Stream API**:通过 Java Stream 的 `map()` 方法将对象转换为组合键,再用 `collect(Collectors.toSet())` 提取唯一。 3. **处理动态属性**:如果属性数量不确定,可通过反射或 Map 动态构建组合键(但需注意性能)。 下面是一个完整示例,假设有一个 `Person` 类包含 `name` `age` 属性,我们需要提取唯一的 `(name, age)` 组合: ```java import java.util.*; import java.util.stream.Collectors; public class UniqueAttributesExtractor { // 步骤1: 定义组合键类,覆盖 equals hashCode static class PersonKey { private String name; private int age; public PersonKey(String name, int age) { this.name = name; this.age = age; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PersonKey personKey = (PersonKey) o; return age == personKey.age && Objects.equals(name, personKey.name); } @Override public int hashCode() { return Objects.hash(name, age); } @Override public String toString() { return "(" + name + ", " + age + ")"; } } public static void main(String[] args) { // 示例数据:List 包含重复组合 (Alice,30) List<Person> persons = Arrays.asList( new Person("Alice", 30), new Person("Bob", 25), new Person("Alice", 30), // 重复项 new Person("Charlie", 25) ); // 步骤2: 使用 Stream 提取唯一组合 Set<PersonKey> uniqueKeys = persons.stream() .map(p -> new PersonKey(p.getName(), p.getAge())) // 转换为组合键 .collect(Collectors.toSet()); // 收集到 Set 确保唯一 System.out.println("唯一组合: " + uniqueKeys); // 输出: 唯一组合: [(Alice, 30), (Bob, 25), (Charlie, 25)] } } // 辅助类 class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } } ``` #### 关键说明: - **组合键类**:`PersonKey` 类通过 `equals()` `hashCode()` 确保属性组合的唯一性。例如,`(Alice, 30)` `(Alice, 30)` 被视为相同键[^1]。 - **Stream API 优势**:使用 `Collectors.toSet()` 自动去重,时间复杂度接近 $O(n)$(依赖哈希冲突)。 - **动态属性处理**:如果属性数量不固定,可用 `Map<String, Object>` 存储属性,但需手动实现哈希逻辑: ```java Set<Map<String, Object>> uniqueCombinations = persons.stream() .map(p -> { Map<String, Object> keyMap = new HashMap<>(); keyMap.put("name", p.getName()); keyMap.put("age", p.getAge()); return keyMap; }) .collect(Collectors.toSet()); ``` - **注意事项**:确保组合键类不可变(final 字段),避免哈希变化导致错误。 类似集合操作中,正确实现 `equals()` `hashCode()` 是保证唯一性的核心,这在排序合并实体类时同样重要[^1][^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值