通用对象比较工具类-GeneralComparator

开发者福利!热门AI工具限时免费用 购周边即赠Coding Plan Lite,Claude Code、Cursor等20+工具畅享,效率翻倍! 阅读详情


由于公司有同步数据的逻辑,涉及到对大批量数据的对比,选择性覆盖,需要对许多不同的数据Beans进行对比。

以前都是针对不同对象重写equals方法,面对大量不同值对象,需要重写很多,比较麻烦,而且重写equals方法大多也只是变量值进行比较。;

有看过别人写的一些,很多都很不理想。。So 一言不合就写个工具类


简单的逻辑

1、判断类型,基本类型、集合、对象分别处理;

2、基本类型直接判断,集合取出后再判断,对象则利用反射获取成员变量,递归取值;

3、没了

也许看起来两个对象判空的时候写的冗长,没有什么与或或者其他会让代码看起来简洁漂亮的写法;
但我觉得这样的朴素的写法可以让比较次数降到最低;

入口:传入两个值对象,并对属性进行分类

/**
     * 同为空/都不为空:true
     */
    public static boolean compareObject(Object head, Object tail) {
        if (head == null) {
            if (tail != null) {
                return false;
            } else {
                return true;
            }
        } else {
            if (tail == null) {
                return false;
            }
        }
        if (head.getClass() != tail.getClass()) {
            return false;
        }
        if (head.equals(tail)) {
            return true;
        }
        if (head.getClass() == String.class) {
            return head.equals(tail);
        } else if (head.getClass() == Integer.class) {
            return (int) head == (int) tail;
        } else if (head.getClass() == Boolean.class) {
            return (boolean) head == (boolean) tail;
        } else if (head.getClass() == Long.class) {
            return (long) head == (long) tail;
        } else if (head.getClass() == Double.class) {
            return (double) head == (double) tail;
        } else if (List.class.isAssignableFrom(head.getClass())) {
            return compareList((List) head, (List) tail);
        } else if (Map.class.isAssignableFrom(head.getClass())) {
            return compareMap(head, tail);
        }
        Field[] fields = head.getClass().getDeclaredFields();
        for (Field field : fields) {
//            Class cls = field.getType();
            Object o1 = getFieldValue(head, field);
            Object o2 = getFieldValue(tail, field);
            boolean result = compareObject(o1, o2);
            if (!result) {
                return false;
            }
            continue;
        }
        return true;
    }

获取field值

    private static Object getFieldValue(Object bean, Field field) {
        try {
            field.setAccessible(true);
            Object value = field.get(bean);
            return value;
        } catch (IllegalAccessException ace) {
            ace.printStackTrace();
            return null;
        }
    }

比较List :List中仍可存储类型的数据,所以使用compareObject方法来比较

private static boolean compareList(List head, List tail) {
        if (head == null) {
            if (tail == null || tail.isEmpty()) {
                return true;
            } else {
                return false;
            }
        } else {
            if (tail == null) {
                return head.isEmpty();
            }
        }
        if (head.isEmpty() && tail.isEmpty()) {
            return true;
        }
        if (head.size() != tail.size()) {
            return false;
        }
        for (int i = 0; i < head.size(); i++) {
            boolean result = compareObject(head.get(i), tail.get(i));
            if (!result) {
                return false;
            }
        }
        return true;
    }

比较Map:Map中没有存储其他类型,均为基本类型,所以就偷懒直接equals比较了

 private static boolean compareMap(Object head, Object tail) {
        if (head == null) {
            if (tail == null) {
                return true;
            } else {
                boolean isEmpty = ((HashMap) tail).isEmpty();
                if (isEmpty) {
                    return true;
                } else {
                    return false;
                }
            }
        } else {
            if (tail == null) {
                boolean isEmpty = ((HashMap) head).isEmpty();
                if (isEmpty) {
                    return true;
                } else {
                    return false;
                }
            }
        }
        HashMap srcMap = (HashMap) head;
        HashMap tarMap = (HashMap) tail;
        if (srcMap.keySet().isEmpty() && tarMap.keySet().isEmpty()) {
            return true;
        }
        if (srcMap.keySet().size() != tarMap.keySet().size()) {
            return false;
        }
        for (String key : srcMap.keySet()) {
            if (!tarMap.containsKey(key)) {
                return false;
            }
            Object vSrc = srcMap.get(key);
            Object vTar = tarMap.get(key);
            if (!vSrc.equals(vTar)) {
                return false;
            }
        }
        return true;
    }

到这以及可以满足绝大部分的数据类型了,而且不论你数据多复杂,嵌套有多深。
没有short、char等,因为项目中没有,集合使用List、Map,其他也没有使用,所有就没有加入;

需要注意:
Object    :    true  :  Null && Null
Set    :    true  :  Null && Null , Empty && Empty ,  Empty && Null
下面是测试用,基本覆盖每个分支

public class TestEquals {
    public static void main(String args[]) {
        School school1 = getTestBean(0);
        School school2 = getTestBean(1);
        long start = System.currentTimeMillis();
        boolean result = GeneralComparator.compareObject(school1, school2);
        long end = System.currentTimeMillis();
        System.out.print(result + " --- " + (end - start));
    }

    private static School getTestBean(int index) {
        School school1 = new School();
        school1.id = 3;
        if (index == 1) {
//            school1.id = 4;
        }
        ArrayList teacher1 = new ArrayList<>();
        Teacher t1 = new Teacher();
        t1.setTeakcherTitle("ma");
        if (index == 1) {
//            t1.setTeakcherTitle("mas");
        }
        if (index == 1) {
//            teacher1.add(t1);
        }
        teacher1.add(t1);
        school1.teacherList = teacher1;

        ArrayList list = new ArrayList();
        list.add("list_1");
        list.add("list_2");
        list.add("list_4");
//        if (index == 1) {
//            list.add("list_4");
//        }
        school1.setSchsoolId(list);
//
        HashMap map1 = new HashMap();
        map1.put("ma2", "2");
        map1.put("ma3", "22");
        if (index == 1) {
//            map1.put("ma3", "2d2");
        }
        school1.map = map1;

        ArrayList> arrayMap = new ArrayList<>();
        arrayMap.add(map1);
        if (index == 1) {
//            map1.put("ma2d","s2");
//            arrayMap.add(map1);
        }
        school1.arrayMap = arrayMap;
        return school1;
    }
}

class School {
    public int id;

    private ArrayList schsoolId;

    public HashMap map;
    public ArrayList teacherList;

    public ArrayList> arrayMap;

    public ArrayList getSchsoolId() {
        return schsoolId;
    }

    public void setSchsoolId(ArrayList schsoolId) {
        this.schsoolId = schsoolId;
    }
}

class Teacher {

    public String teakcherTitle;


    public String getTeakcherTitle() {
        return teakcherTitle;
    }

    public void setTeakcherTitle(String teakcherTitle) {
        this.teakcherTitle = teakcherTitle;
    }
}


java后端比较同类的两个对象的字段差异的项目内的三种实现的比较 项目内有个需求,对导入的数据行,通过流程将数据下发到具体的业务人员端,由业务人员进行核对,然后由移动端APP,将核对后的前后差异的数据挂载到流程中去。需要提交的信息格式为“[{"fieldDesc":"姓名","newValue":"李四","fieldName":"cnName","oldValue":"张三"}]”,将每个不同的字段信息对比信息,包装到数组中统一挂载到流程中。本例介绍了项目内对象对比的三种实现方式,并对比了其中的实现差异,流程的相关操作不在本例介绍范围内。 阅读详情

相关推荐

比较2个实体对象——CompareUtil工具类

package com.lmp.utils; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.sql.Timestamp; import java.util.*; public class CompareUtil { /** * 比较两个实体属性值(同一对象类型),返回一个boolean,true则

leomoon 2549

java对象对比工具 自定义注解对象属性对比 支持递归调用 无三方包纯原生工具 简单实用 反射来对比对象的差异 增强字典说明

java对象对比工具 纯原生工具 注解反射

CC学java 1032

对象字段变化比较工具

对象更改比较工具类,用于比较字段变化值,抛砖引玉,欢迎指正。

java对象比较工具类(CompareUtils)

使用Comparator// 使用自定义 Comparator 比较两个对象// 比较两个对象是否相等CompareUtils是一个Java对象比较工具类,用于比较两个对象的相等性。该工具类提供了多个方法来比较对象的属性值是否相等,以及比较对象的引用是否相等。equals()方法:比较两个对象的属性值是否相等,如果所有属性值都相等,则返回true,否则返回false。deepEquals()方法:递归比较两个对象的属性值是否相等,如果所有属性值都相等,则返回true,否则返回false。

Flying_Fish_roe的博客 1550

工作记录:Java通过反射比较两个具有相同属性的对象属性值差异的工具类

getDifferentProperty(T oldObj , T newObj , String... ignoreProperties)方法中ignoreProperties参数可以过滤掉不需要对比的属性(支持过滤多个属性,用逗号隔开)。方法返回的结果是一个包含属性名、新旧属性值的集合,如果不过滤class,对象的类型也会对比并返回。

qq_42715683的博客 1114

Java工具类:CompareUtils(比较对象字段值变化)

目录 前言 示例引入 工具文件 CompareUtils Compare CompareNode 前言 我们在工作中,可能会在日志中记录数据的变化情况,这样可以有助于运维人员对问题排查。 或者在公共处理的数据增加一个日志页面,记录每次修改的变化。比如:小王在 2022-05-05 23:58:27 时间点修改了年龄,把 28 改为了 18), 这样也可以方便用户的数据追踪,这样公共数据一旦出了问题,我们从日志进行跟踪,那么最后是谁造成的,也就一目了然。 可见,展示字段值的变化..

小白一个 1万+

(二十)Java工具类Diffable、DiffBuilder、Diff比较对象的区别及建造者模式详解

建造者模式(Builder pattern)使用多个简单的对象一步一步的构建成一个复杂的对象,这种类型的设计模式属于创建型模式,他提供了一种创建对象的最佳方式; 一个Builder类会一步一步的构造最终的对象,该Builder类是独立于其它对象的; 建造者模式主要是解决在软件系统中,有时候面临者一个复杂对象的创建工作,其通常由各个部分的子对象用一定的算法构成,由于需求的变化,这个复杂对象的各个部分...

OceanSky的专栏 5212

java比较两个实体类及属性差异工具类(简版)

思路:通过反射技术获取所有属性并进行对比,详细步骤如下: package com.app.business.utils; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import java.sql.Timestamp; import...

AnNong 5956

java2个对象比较不同_Java比较两个对象的属性有哪些不同

创建工具类通过反射获取类型字段并且通过getSuperclass获取父类的字段,然后再通过两个对象进行字段值比较。public class ClassInstanceCompareUtil {/*** 比较对象所有字段并把差异字段存入新的对象** @return*/public static T compareInstance(T source, T target) throws Illega...

weixin_29000891的博客 1142

说说在 Java 中如何比较两个对象

Common Lang 中的 Builder 包内提供了一个 DiffBuilder 类,可以比较两个对象,并返回不同的部分。 首先在要比较对象的类中实现 Diffable 接口,然后实现 DiffResult diff(T obj) 方法。 在DiffResult diff(T obj) 方法中,新建一个 DiffBuilder 对象,把需要比较的类属性一一放入 DiffBuilder 中。 DiffBuilder 的构造函数有三个入参,lhs 是当前对象,rhs 是要比较对象,style 是比

读万卷书,行万里路 1628

(类比较器)java对比两个相同实体类中属性的值的差异

平时经常会遇到这种情况,比如修改一个单子,需要记录修改记录,这就需要做前后对比,所以自己定义了一个工具类,细节还可以优化,希望大家提出宝贵的意见。 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface AnjiDescription { /** * 加上注解默认对比 * @return */ String value(); .

Fupengyao的博客 1万+

java实现对象对比工具类

目录说明对比示例/结果源码 说明 此工具类对比两个Java对象相同属性以及不同属性 对比示例/结果 对比示例,可以对比实体,实体中嵌套实体,实体中嵌套集合等 { "id":"", "username":"", "age":0, "address":[ { "province":"", "city":"", "disrtict":"" } ], "details":{ "sex":"", "mobile":"" } } 一下对比结果(更多测试可使用下方源码进行

flyq_coffee 1911

java 工具类: CompareUtils(比较对象字段值变化)

我们在工作中,可能会在日志中记录数据的变化情况或者在公共处理的数据增加一个日志页面,记录每次修改的变化。我们可以根据CompareUtils工具类比较数据前后发生了怎样的变化, 这样我们就可以知道数据做了哪些改变./*** 字段标记注解*//*** 字段名称*/

m0_61682705的博客 2363

如何比较两个对象字段的差异,对象比较工具类实现

工具类,用于比较两个对象之间的差异,并将差异以Map的形式返回。该类的主要方法是diffToMap,它接受两个对象作为输入,并可选地接受一个忽略字段的列表。该方法首先将输入对象转换为JSON字符串,然后将JSON字符串转换为Map,最后比较两个Map的差异并返回结果。该类还包含一些辅助方法,如和doCompare,用于处理JSON到Map的转换和比较两个Map的差异。

fhey的博客 947

Java对象通用比对工具

本文提供一种通用java对象比对方法,并支持自定义的过滤哪些字段无需比较

(づ ̄ 3 ̄)づxl 1687

对象比较

在程序设计的过程中,经常会遇到需要进行排序的东西,对于一般的数字排序,有着各式各样的排序函数可以使用,但是他们经常是采取默认的方法进行排序的,当我么需要进行自定义的排序的时候,我们就需要自定义一个排序的方法,也就用到了对象比较器。对象比较器可以自己定义比较对象按照某一属性进行排序,实现该方法有两种途径: 实现Comparable接口 实现Comparator接口 对于这两种方法分别用两个实例代码举

zhuxinquan的博客 801

Java中的比较器(Comparator)

Comparator接口中有一个compare()方法,它接受两个对象作为参数,并返回一个int值,表示它们的顺序。在这个例子中,我们定义了一个StringComparator类,实现了Comparator接口中的compare()方法,用于按字典序比较两个字符串的大小。例如,如果我们希望在一个Set中保存自定义对象,而这些对象的相等性不是基于对象的引用相等,而是基于对象的某些属性相等,我们可以使用Comparator来实现equals()和hashCode()方法。

weixin_64353239的博客 4883

Comparator工具类对list对象多字段进行排序

第一行输入一个整数n,表示员工列表中员工的人数,接下来的n行,分别输入 员工的姓名、职级、工作年限、和工资信息,各项信息之间用空格分隔。

奔跑的小猫 6333

JAVA 可变参数、比较器(Comparable、Comparator)、数组工具类(Arrays)、集合工具类(Collections) Java第十四天(一)

JAVA第十四天(一)可变(动态)参数比较器(Comparable、Comparator)工具类工具类(Arrays)  将数组转换成字符串  对任意数组排序  对任意数组做二分法查找  将数组转换成List 工具类(Collections) 可变(动态)参数   当一个成员方法内需要传入多个同类型的参数时,可以使用可变参数。   语法:  其中参数类型 ... p参数是一个指定参数类型的数组(...

admin_233的博客 621
上一篇: 【微信支付】签名错误,参数错误
下一篇: Android Studio 调试 Native 、NDK,C
蛋蛋专属
博客等级 码龄16年 10粉丝 16原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值