当前位置: 首页 > news >正文

Java对象属性比较工具类(可用)

摘要:

在Java开发过程中,我们经常需要对两个对象的属性进行对比。本文将介绍一款实用的工具类BeanCompareUtil,它可以帮助我们高效地进行对象属性比较,并详细讲解其实现原理及使用方法。
一、背景
在日常开发中,我们经常遇到以下场景:比较两个对象的属性是否相等。如果手动编写代码进行属性比较,不仅效率低下,而且容易出错。为此,本文将介绍一款强大的工具类BeanCompareUtil,它可以帮助我们快速、准确地比较对象属性。

// 假设 BizAppealTrack 有 getter 方法
String taskNum = bizAppealTrack.getTaskNum();
String nodeTime = bizAppealTrack.getNodeTime();
String deptName = bizAppealTrack.getDeptName();
String content = bizAppealTrack.getContent();boolean isSameData = tempBizAppealTrackList.stream()
.anyMatch(appealTrack -> {return Objects.equals(taskNum, appealTrack.getTaskNum()) &&Objects.equals(nodeTime, appealTrack.getNodeTime()) &&Objects.equals(deptName, appealTrack.getDeptName()) &&Objects.equals(content, appealTrack.getContent());
});

二、BeanCompareUtil实现原理

BeanCompareUtil工具类主要依赖于Java反射机制和Spring框架的ReflectionUtils工具类。以下是BeanCompareUtil的核心实现原理:

  1. 使用Map缓存字段信息,提高查找效率。
  2. 通过反射获取指定类的所有字段,并存储到缓存中。
  3. 比较两个对象指定字段的值是否相等。
    三、BeanCompareUtil使用方法
  4. 引入依赖
    首先,在项目中引入Spring框架依赖:
<dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>5.3.9</version>
</dependency>

创建工具类

将以下代码复制到项目中,创建BeanCompareUtil类:

// BeanCompareUtil代码
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;public class BeanCompareUtil {// 使用缓存来存储字段,避免重复查找private static final Map<Class<?>, Map<String, Field>> fieldCache = new HashMap<>();/*** equalsByFields方法比较两个对象中指定字段的值是否相等。* 如果源对象或目标对象为null,则直接返回比较结果。* 如果源对象和目标对象的类型不同,则返回false。* 否则,使用缓存的字段映射来获取字段,并比较它们的值。* 如果任何字段的值不相等,则返回false。* 如果所有字段的值都相等,则返回true。** @param src        源对象* @param target     目标对象* @param fieldNames 需要比较的字段名称数组* @return 如果指定字段相等返回true,否则返回false*/public static boolean equalsByFields(Object src, Object target, String... fieldNames) {// 如果源对象或目标对象为null,则直接返回比较结果if (src == null || target == null) {return src == target;}// 如果源对象和目标对象的类型不同,则返回falseif (!src.getClass().equals(target.getClass())) {return false;}// 使用缓存的字段映射来获取字段Map<String, Field> fields = getFieldMap(src.getClass());for (String fieldName : fieldNames) {Field field = fields.get(fieldName);// 如果字段未找到,则抛出异常if (field == null) {throw new IllegalArgumentException("Field " + fieldName + " not found in class " + src.getClass());}// 使字段可访问ReflectionUtils.makeAccessible(field);// 获取字段值并比较Object srcValue = ReflectionUtils.getField(field, src);Object targetValue = ReflectionUtils.getField(field, target);// 如果字段值不相等,则返回falseif (!Objects.equals(srcValue, targetValue)) {return false;}}// 如果所有字段的值都相等,则返回truereturn true;}/*** getFieldMap方法获取指定类的所有字段映射。* 使用缓存来避免重复查找字段。** @param clazz 类的Class对象* @return 包含字段映射的Map*/private static Map<String, Field> getFieldMap(Class<?> clazz) {// 使用缓存来获取字段映射Map<String, Field> fieldMap = fieldCache.computeIfAbsent(clazz, k -> {Map<String, Field> newFieldMap = new HashMap<>();// 获取类的所有声明字段Field[] declaredFields = clazz.getDeclaredFields();// 遍历字段并添加到映射中for (Field field : declaredFields) {newFieldMap.put(field.getName(), field);}// 返回新的字段映射return newFieldMap;});// 返回缓存的字段映射return fieldMap;}// main 方法与之前相同// public static void main(String[] args) {//     // 示例对象//     Person p1 = new Person("Alice", 30);//     Person p2 = new Person("Alice", 30);//     Person p3 = new Person("Bob", 25);////     // 比较p1和p2的name字段是否相等//     boolean isSame = equalsByFields(p1, p2, "name", "age");//     System.out.println("p1和p2的字段是否相等: " + isSame);////     // 比较p1和p3的name字段是否相等//     isSame = equalsByFields(p1, p3, "name", "age");//     System.out.println("p1和p3的字段是否相等: " + isSame);// }
}

使用示例

以下是一个使用BeanCompareUtil进行对象属性比较的示例:

public class Main {public static void main(String[] args) {// 示例对象Person p1 = new Person("Alice", 30);Person p2 = new Person("Alice", 30);Person p3 = new Person("Bob", 25);// 比较p1和p2的name字段是否相等boolean isSame = BeanCompareUtil.equalsByFields(p1, p2, "name", "age");System.out.println("p1和p2的字段是否相等: " + isSame);// 比较p1和p3的name字段是否相等isSame = BeanCompareUtil.equalsByFields(p1, p3, "name", "age");System.out.println("p1和p3的字段是否相等: " + isSame);}
}
class Person {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}// 省略getter和setter方法
}

运行结果

p1和p2的字段是否相等: true
p1和p3的字段是否相等: false

四、总结

BeanCompareUtil是一款实用的Java对象属性比较工具类,它基于反射机制和Spring框架的ReflectionUtils工具类实现。通过使用BeanCompareUtil,我们可以轻松地进行对象属性比较,提高开发效率。在实际项目中,我们可以根据需求对BeanCompareUtil进行扩展,以满足更多场景的需求。

补充测试

// 下面是一个`main`测试案例,用于校验`BeanCompareUtil`类的健壮性。这个测试案例将创建几个对象,并对它们进行字段比较。测试案例会包括以下几种情况:
// 1. 比较相同字段值的对象。
// 2. 比较不同字段值的对象。
// 3. 比较一个字段值为`null`和一个非`null`的对象。
// 4. 比较两个`null`对象。
// 5. 比较一个`null`对象和一个非`null`对象。
// 6. 比较不同类型的对象。
// 7. 比较不存在的字段。public class BeanCompareUtilTest {public static void main(String[] args) {// 示例对象Person p1 = new Person("Alice", 30);Person p2 = new Person("Alice", 30);Person p3 = new Person("Bob", 25);Person p4 = new Person(null, 30);Person p5 = null;Person p6 = new Person("Alice", 30);OtherClass oc = new OtherClass("Alice", 30);// 比较p1和p2的name和age字段是否相等boolean isSame = BeanCompareUtil.equalsByFields(p1, p2, "name", "age");System.out.println("p1和p2的字段是否相等: " + isSame);// 比较p1和p3的name和age字段是否相等isSame = BeanCompareUtil.equalsByFields(p1, p3, "name", "age");System.out.println("p1和p3的字段是否相等: " + isSame);// 比较p1和p4的name字段是否相等(p4的name为null)isSame = BeanCompareUtil.equalsByFields(p1, p4, "name");System.out.println("p1和p4的name字段是否相等: " + isSame);// 比较p5和p5(两个null对象)isSame = BeanCompareUtil.equalsByFields(p5, p5, "name", "age");System.out.println("p5和p5的字段是否相等: " + isSame);// 比较p1和p5(p5为null)isSame = BeanCompareUtil.equalsByFields(p1, p5, "name", "age");System.out.println("p1和p5的字段是否相等: " + isSame);// 比较p1和oc(不同类型的对象)try {isSame = BeanCompareUtil.equalsByFields(p1, oc, "name", "age");System.out.println("p1和oc的字段是否相等: " + isSame);} catch (IllegalArgumentException e) {System.out.println("比较p1和oc时发生错误: " + e.getMessage());}// 比较p1和p6的不存在的字段try {isSame = BeanCompareUtil.equalsByFields(p1, p6, "nonExistentField");System.out.println("p1和p6的nonExistentField字段是否相等: " + isSame);} catch (IllegalArgumentException e) {System.out.println("比较p1和p6的nonExistentField字段时发生错误: " + e.getMessage());}}// Person类定义public static class Person {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}// Getters and Setterspublic String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}// OtherClass类定义public static class OtherClass {private String name;private int age;public OtherClass(String name, int age) {this.name = name;this.age = age;}// Getters and Setterspublic String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}
}

图片.png


http://www.mrgr.cn/news/14047.html

相关文章:

  • 【中秋特惠】南卡Runner Pro5:送给家人的科技健康礼!
  • 不用async与await将异步函数改为同步函数
  • 【递归回溯之floodfill算法专题练习】
  • 了解CSS中的BFC
  • 华为设备默认密码
  • Lombok组件的使用
  • E29.【C语言】练习:sizeof和strlen的习题集(A)
  • matlab 将数组从左向右翻转
  • 电子电气架构 --- 车载网简史(上)
  • 迷雾大陆辅助:VMOS云手机助力升级装备系统秘籍!
  • Python——xml.etree.ElementTree
  • SQL 注入之 sqlmap 实战
  • (二)、软硬件全开源智能手表,可全面高精度采集生命体征数据,进行健康检测。(HealthyPi Move)
  • 使用Python将应用程序添加进Linux/Windows/MacOS登录项
  • 异或+与+或
  • JavaWeb学习——原理篇学习
  • WHAT - 通过 react-use 源码学习 React(UI 篇)
  • 新华三H3C HCL配置IS-IS基本配置
  • 揭秘无线领夹麦克风五大行业隐秘:音质失真、隐私泄露需警惕!
  • 【kafa系列】kafka如何保证消息不丢失