添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Java如何比较两个对象并获取不相等的字段详解

作者:dadiyang

这篇文章主要给大家介绍了关于Java如何比较两个对象并获取不相等的字段以及JAVA判断(获取)两个相同对象不同的数据的相关资料,文中通过实例代码介绍的非常详细,对大家学习或者使用java具有一定的参考学习价值,需要的朋友可以参考下

在工作中,我们经常会遇到这样的需求——比较两个对象是否相等,如果不相等的话,取出不相等的字段。

以下这些场景都需要我们对一个对象进行比较:

  • 做单元测试断言对象是否相等
  • 前端要求对不相等的字段进行高亮显示
  • 这种需求其实是非常简单的,但是如何优雅地解决这一类需求呢?

    通常的做法是重写对象的 equals 方法。但是重写 equals 方法有很多缺点,例如:

  • 每次对象属性有变更,一定要记得再重写(放心,你一定会忘记的)
  • 每个对象只能有一个 equals 方法,但是可能你会需要不同的比对规则
  • 只能对比两个对象是否相等,无法具体知道哪个属性不等
  • 自动生成的 equals 方法无法基于 getter 方法进行比对
  • 对象来自第三方依赖,无法重写 equals 方法
  • 因此,实现一个通用的比对器可以减少很多不必要的麻烦,帮助我们很好地完成这一类的需求。

    我是在做数据同步的时候有这个需求,我要将数据库的数据通过一定的规则导入到 ES 中,导入完成之后,如何比对两边的数据是否一致呢?这时候一个好用的比对器就是我非常好的帮手。

    另外,我在做单元测试的时候发现,经常会需要将被测方法的返回值和期望的结果做 assertEquals 断言这时这个比对器也非常有帮助。我发现很多同事经常会遇到类似的需求。

    于是,我找时间自己实现了一下。

    使用反射对传入的对象进行比对,提供了基于字段的比较器和基于 Getter 方法的对比器,并且充分考虑扩展性,使用者可以重写字段的比对规则。功能相对简单,代码实现也不难,而且做了很多注释,具体实现可以直接查看源码。

    项目地址:https://github.com/dadiyang/equator

    UML图:

    因为已经上传到了 maven 仓库中,我们使用非常方便:

    添加 maven 依赖

    <dependency> <groupId>com.github.dadiyang</groupId> <artifactId>equator</artifactId> <version>1.0.3</version> </dependency>

    初始化并调用方法

    Equator equator = new GetterBaseEquator(); User user1 = new User(...); User user2 = new User(...); // 判断属性是否完全相等 equator.isEquals(user1, user2); // 获取不同的属性 List<FieldInfo> diff = equator.getDiffFields(user1, user2);

    我们可以通过继承并重写 isFieldEquals 方法自定义比对规则,例如我们在做单元测试的时候,对于 Date 类型的字段的比对,通常数据库不保存毫秒数,而我们 new 出来的 Date 对象则包含了毫秒数,因此我们在对包含 Date 类型字段的对象做比对的时候需要忽略日期的毫秒数。这时就可以通过重写isFieldEquals 方法来自定义了:

    * 日期在数据库不保存毫秒数,因此需要特殊处理,比对时间时,忽略毫秒数 * @author dadiyang * @date 2019/3/23 public class MmInsensitiveEquator extends GetterBaseEquator { @Override protected boolean isFieldEquals(FieldInfo fieldInfo) { if (fieldInfo.getFirstVal() instanceof Date) { Date first = (Date) fieldInfo.getFirstVal(); Date second = (Date) fieldInfo.getSecondVal(); if (Objects.equals(first, second)) { return true; // 忽略毫秒数 return Objects.equals(Math.round(first.getTime() / 1000), Math.round(second.getTime() / 1000)); return super.isFieldEquals(fieldInfo);

    对象比对是一个非常小的需求,通常我们只会写一个工具类来完成。但是写一个工具类在各个项目间随处拷贝,非常不优雅,给整个团队带来很多不必要的维护成本。而且扩展性比较差,有任何差异就需要写很多代码去实现。

    这时,如果我们从具体解决某一个需求的视角上升到解决一类需求,那么就能想出更加通用和优雅的解决方案了。一个个具体的需求是无穷无尽的,以有限的人生去解决无限的需求,殆矣;但是将它们归类之后,我们会发现,需求的种类是有限的。

    附:JAVA判断(获取)两个相同对象不同的数据

    项目中需要获取修改前和修改后的不同数据并进行保存。

    不知道高大上的做法,就写个工具类。

    package com.shiyan.utils.object; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang3.StringUtils; public class GetDifference { public static Map<String, String> getUser(Object a, Object b) throws IllegalArgumentException, IllegalAccessException { Map<String, String> map = new HashMap<String, String>(); Field[] declaredFields2 = a.getClass().getDeclaredFields(); Field[] declaredFields23 = b.getClass().getDeclaredFields(); StringBuilder xiugaiqian = new StringBuilder(); StringBuffer xiugaihou = new StringBuffer(); for (int i = 0; i < declaredFields2.length; i++) { declaredFields2[i].setAccessible(true); declaredFields23[i].setAccessible(true); if (declaredFields2[i].get(a) != null && declaredFields23[i].get(b) != null) { if (!declaredFields2[i].get(a).equals(declaredFields23[i].get(b))) { xiugaiqian.append(declaredFields2[i].getName() + ":" + declaredFields2[i].get(a)).append(","); xiugaihou.append(declaredFields23[i].getName() + ":" + declaredFields23[i].get(b)).append(","); } else if (declaredFields2[i].get(a) == null && declaredFields23[i].get(b) != null) { xiugaiqian.append(declaredFields2[i].getName() + ":" + null).append(","); xiugaihou.append(declaredFields23[i].getName() + ":" + declaredFields23[i].get(b)).append(","); } else if (declaredFields2[i].get(a) != null && declaredFields23[i].get(b) == null) { xiugaiqian.append(declaredFields2[i].getName() + ":" + declaredFields2[i].get(a)).append(","); xiugaihou.append(declaredFields23[i].getName() + ":" + null).append(","); if (StringUtils.isNoneBlank(xiugaiqian.toString()) && StringUtils.isNoneBlank(xiugaihou.toString())) { map.put(xiugaiqian.toString().substring(0, xiugaiqian.length() - 1), xiugaihou.toString().substring(0, xiugaihou.length() - 1)); return map; * Description: * @Author:xieyuxin * @param * @param 设定文件 * @throws * @return String * @Exception 异常对象 package com.shiyan.test; import java.util.Map; import com.shiyan.utils.object.GetDifference; public class ObjectGetEerro { public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException { Persion p1 = new Persion.Builder().age(12).name("张三").t("2018-10-20").build(); Persion p2 = new Persion.Builder().age(16).name("1111").build(); Map<String, String> user = GetDifference.getUser(p1, p2); for(Map.Entry<String, String> entry : user.entrySet()){ System.out.println("修改前 :" + entry.getKey()); System.out.println("修改后 :" + entry.getValue());

    到此这篇关于Java如何比较两个对象并获取不相等字段的文章就介绍到这了,更多相关Java比较两个对象内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

    您可能感兴趣的文章:
  • springcloud部署提示 找不到url的解决
    springcloud部署提示 找不到url的解决
    2022-01-01
  • java实现简单石头剪刀布小游戏
    java实现简单石头剪刀布小游戏
    2022-01-01
  • Springboot-Shiro基本使用详情介绍
    Springboot-Shiro基本使用详情介绍
    2022-01-01
  • Java中集合List、Set和Map的入门详细介绍
    Java中集合List、Set和Map的入门详细介绍
    2022-01-01
  • springboot集成mybatis plus和dynamic-datasource注意事项说明
    springboot集成mybatis plus和dynamic-data
    2022-01-01
  • 详解java关于对象的比较
    详解java关于对象的比较
    2022-01-01
  • springboot+dynamicDataSource动态添加切换数据源方式
    springboot+dynamicDataSource动态添加切换数据源方
    2022-01-01
  • SpringBoot +DynamicDataSource切换多数据源的全过程
    SpringBoot +DynamicDataSource切换多数据源的全
    2022-01-01
  • 美国设下计谋,用娘炮文化重塑日本,已影响至中国
    美国设下计谋,用娘炮文化重塑日本,已影响至中国
    2021-11-19
  • 时空伴随者是什么意思?时空伴随者介绍
    时空伴随者是什么意思?时空伴随者介绍
    2021-11-09
  • 工信部称网盘企业免费用户最低速率应满足基本下载需求,天翼云盘回应:坚决支持,始终
    工信部称网盘企业免费用户最低速率应满足基本下载需求,天翼云盘回应:坚决支持,始终
    2021-11-05
  • 2022年放假安排出炉:五一连休5天 2022年所有节日一览表
    2022年放假安排出炉:五一连休5天 2022年所有节日一览表
    2021-10-26
  • 电脑版 - 返回首页

    2006-2023 脚本之家 JB51.Net , All Rights Reserved.
    苏ICP备14036222号