記一次lombok踩坑記

引言

今天中午正在帶着耳機遨遊在代碼的世界裏,被運營在羣裏@了,氣沖沖的反問我最近有刪生產的用戶數據的嗎?我確定客氣的回答道沒有呀?生產的數據我怎麼能隨隨便即可以刪除,這但是公司的紅線,再說了我也沒有數據庫的刪除權限啊,不過查詢權限仍是有的。趕忙登上堡壘機,而後去生產數據庫查一下數據,查了一下數據是還在的,嚇死了,數據還在問題就不大了,無非就是應用程序出問題了,趕忙打開代碼查看下,爲何會少了一條用戶數據,看了下代碼貌似沒啥問題就是比較簡單的一個邏輯,直接從DB經過分頁查詢數據給到前端,而後前端負責展現,沒有啥複雜的邏輯。心想確定是前端的問題,確定是他少展現了數據,立馬把問題也甩給了他,讓他幫忙配合一塊兒看看是不是前端的問題,而後本身也仔細看看代碼,不到一分鐘前端說他展現的數據沒有問題,都是後端給到的,沒有漏掉展現的。那就是後端的bug了羅。肉眼望去以爲可能出問題的就是分頁致使的數據丟了。不過這個分頁插件是全公司都在用,應該不至於出問題把,找不到問題只能讓測試幫忙在測試環境試試,看看是否能夠復現。前端

測試環境復現

仔細看了一眼,竟然有個去重的方法,去重邏輯也比較簡單就是把list經過轉爲set去下重,看下來應該就是這個去重方法有問題了
大體寫了單元測試模仿了下生產的數據,大體邏輯以下:java

public static void main(String[] args) {
        Set<UserDTO> userSet = new HashSet<>();
        UserDTO userDTO = new UserDTO();
        userDTO.setId(1);
        userDTO.setUserName("java金融");

        UserDTO userDTO1 = new UserDTO();
        userDTO1.setId(2);
        userDTO1.setUserName("java金融");
        userSet.add(userDTO);
        userSet.add(userDTO1);
        System.out.println(userSet.size());
        System.out.println(userDTO1.equals(userDTO));
    }

    @Data
    static class UserDTO extends BaseDTO {
        private String userName;
    }
    @Data
    static class BaseDTO {
        private Integer id;
    }

咱們能夠輸出結果set集合的長度是1,user1user2 是相等的,明明兩個userID是不同的,爲什麼會相等,咱們知道set能夠去重
是由於Set的操做,都是經過操做map來實現的,setadd其實就是調用mapput方法,mapput方法我相信你們應該都去看過其源碼,這裏就不詳細再說了,大概流程就是經過key經過hash算法定位到數組的下標,先判斷keyhash是否相等,若是相等再去判斷key的value相等,若是都相等就會覆蓋原來的值。咱們上面這個例子就是對象的hashvalue都相等致使,可是咱們的兩個對象user1user2 應該是不等的,由於ID不等,那爲何會相等列?咱們仔細看下上面的代碼,咱們使用了lombok裏面@Data註解,咱們能夠看看這個註解幫咱們生成了哪些方法
在這裏插入圖片描述
在這裏插入圖片描述
經過上面的對比咱們能夠看出@Data註解幫咱們生成了 注在類上,提供類的get、set、equals、hashCode、canEqual、toString方法,這個註解確實比較方便。上面那個bug 就是由於它生成的equals方法有問題,咱們能夠把上述代碼編譯下,而後把class 裏面生成的equals方法拷貝出來看看
在這裏插入圖片描述面試

經過上述生成的代碼咱們能夠看出equals方法只比較了userName這個字段,也就是當前類的字段,並無去比較父類的字段,這就是致使兩個對象相等的緣由,咱們既然找到問題了,那解決問題就比較簡單。算法

解決問題

  • 手動重寫equalshashCode方法,這種方法確定是不推薦的,咱們既然用了lombok就是爲了解放咱們的雙手,是代碼變得更加簡潔。
  • 在比較的類上加上@EqualsAndHashCode(callSuper = true) callSuper = true 會包含父類的equalshashCode方法
    咱們能夠對比下加上@EqualsAndHashCode(callSuper = true)和沒有加上這個註解生成的equals方法的代碼差別。
    在這裏插入圖片描述
    差別點仍是很明顯的,加入了@EqualsAndHashCode(callSuper = true) 會去調用父類的equals方法比較,因此這個註解也可以解決這個問題。
  • 這樣加上註解確實能夠解決問題,可是每一個類上面都要加上這個註解,這也是個體力活。咱們能夠再找找其餘的方案,例若有沒有好比配置文件設置下什麼的,而後就能全局生效了。最終經過查詢資料發現咱們咱們寫一個lombok.config的配置文件放在咱們項目的根目錄下面,內容寫上lombok.equalsAndHashCode.callSuper = call效果等同於@EqualsAndHashCode(callSuper = true),這樣的話咱們就不須要爲每一個類都去加上這個註釋了,至關於在這個項目下面只要用到了@Data註解的類都會爲其加上@EqualsAndHashCode(callSuper = true)經過配置文件的方式就能夠全局生效。

總結

  • 咱們再來回顧下上面的問題,歸根結底仍是因爲對象的equals方法使用不當引發的,因此咱們在若是在判斷自定義對象業務判斷相等的時候須要去重寫下hashCodeequals方法,重寫的時候咱們能夠經過idea來生成,生成後最好仍是去看一眼,看看生成的是否符合咱們的業務要求。數據庫

  • 咱們在工做中操做一些常見的容器類好比Set、Map等來實現一些咱們本身的業務,咱們仍是有必要去看看它們的源碼的,就好比咱們經過Set來進行去重,若是咱們是使用的自定義對象的話,若是沒有重寫hashCodeequals方法的話,去重就會去不成功,咱們只有瞭解了它,才能真正的去用好它。在關於hashCodeequals 阿里巴巴開發手冊也有明確的說到
    在這裏插入圖片描述後端

  • lombok 用起來仍是挺爽的,可是仍是有一些細節須要稍微注意下。使用前能夠大概的去看看它的官網提供的內容,否則出現莫名其妙的問題你都不知道如何下手。這個就有點相似於咱們使用SpringBoot同樣,用起來很是爽,可是若是遇到莫名其妙的bug解決起來就比較頭疼。數組

  • 最後咱們再來回顧幾道關於hashCodeequals的比較常見的面試題?其實若是咱們只要真正看過HashMap的源碼的話,這下面幾個面試題仍是很是簡單的。
    什麼狀況下須要咱們去重寫 方法?
    若是隻重寫equals方法不重寫HashCode能夠嗎?
    equals ,== 和hashcode()的區別?ide

單元測試

結束

  • 因爲本身才疏學淺,不免會有紕漏,假如你發現了錯誤的地方,還望留言給我指出來,我會對其加以修正。
  • 若是你以爲文章還不錯,你的轉發、分享、讚揚、點贊、留言就是對我最大的鼓勵。
  • 感謝您的閱讀,十分歡迎並感謝您的關注。
相關文章
相關標籤/搜索