Java如何比較兩個對象並獲取其中不相等的字段?

聲明:本文屬原創文章,始發於 https://blog.csdn.net/dadiyan...。特此,同步發佈到 sf,轉載請註明出處。前端

寫在前面

在工做中,咱們常常會遇到這樣的需求——比較兩個對象是否相等,若是不相等的話,取出不相等的字段java

如下這些場景都須要咱們對一個對象進行比較:git

  • 數據比對
  • 單元測試斷言對象是否相等
  • 前端要求對不相等的字段進行高亮顯示

這種需求實際上是很是簡單的,可是如何優雅地解決這一類需求呢?github

一般的作法是重寫對象的 equals 方法。可是重寫 equals 方法有不少缺點,例如:數據庫

  • 每次對象屬性有變動,必定要記得再重寫(放心,你必定會忘記的
  • 每一個對象只能有一個 equals 方法,可是可能你會須要不一樣的比對規則
  • 只能對比兩個對象是否相等,沒法具體知道哪一個屬性不等
  • 自動生成的 equals 方法沒法基於 getter 方法進行比對
  • 對象來自第三方依賴,沒法重寫 equals 方法

所以,實現一個通用的比對器能夠減小不少沒必要要的麻煩,幫助咱們很好地完成這一類的需求maven

緣起

我是在作數據同步的時候有這個需求,我要將數據庫的數據經過必定的規則導入到 ES 中,導入完成以後,如何比對兩邊的數據是否一致呢?這時候一個好用的比對器就是我很是好的幫手。ide

另外,我在作單元測試的時候發現,常常會須要將被測方法的返回值和指望的結果作 assertEquals 斷言這時這個比對器也很是有幫助。我發現不少同事常常會遇到相似的需求。工具

因而,我找時間本身實現了一下。單元測試

實現

使用反射對傳入的對象進行比對,提供了基於字段的比較器和基於 Getter 方法的對比器,而且充分考慮擴展性,使用者能夠重寫字段的比對規則。功能相對簡單,代碼實現也不難,並且作了不少註釋,具體實現能夠直接查看源碼。測試

項目地址:https://github.com/dadiyang/e...

UML圖:
Equator UML 圖

使用方法

由於已經上傳到了 maven 倉庫中,咱們使用很是方便:

  1. 添加 maven 依賴
<dependency>
    <groupId>com.github.dadiyang</groupId>
    <artifactId>equator</artifactId>
    <version>1.0.1</version>
</dependency>
  1. 初始化並調用方法
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);
    }
}

後記

對象比對是一個很是小的需求,一般咱們只會寫一個工具類來完成。可是寫一個工具類在各個項目間隨處拷貝,很是不優雅,給整個團隊帶來不少沒必要要的維護成本。並且擴展性比較差,有任何差別就須要寫不少代碼去實現。

這時,若是咱們從具體解決某一個需求的視角上升到解決一類需求,那麼就能想出更加通用和優雅的解決方案了。一個個具體的需求是無窮無盡的,以有限的人生去解決無限的需求,殆矣;可是將它們歸類以後,咱們會發現,需求的種類是有限的

所以解決一類一類問題,能讓咱們擺脫無窮無盡的重複勞動,少加點班,多點時間陪陪家人哦。

相關文章
相關標籤/搜索