一不小心就踩了lombok的坑?
時(shí)間:2021-08-18 08:40:48
手機(jī)看文章
掃描二維碼
隨時(shí)隨地手機(jī)看文章
[導(dǎo)讀]引言今天中午正在帶著耳機(jī)遨游在代碼的世界里,被運(yùn)營在群里@了,氣沖沖的反問我最近有刪生產(chǎn)的用戶數(shù)據(jù)的嗎?我肯定客氣的回答道沒有呀?生產(chǎn)的數(shù)據(jù)我怎么能隨隨便便可以刪除,這可是公司的紅線,再說了我也沒有數(shù)據(jù)庫的刪除權(quán)限啊,不過查詢權(quán)限還是有的。趕緊登上堡壘機(jī),然后去生產(chǎn)數(shù)據(jù)庫查一下數(shù)...
引言
今天中午正在帶著耳機(jī)遨游在代碼的世界里,被運(yùn)營在群里
通過上面的對比我們可以看出
通過上述生成的代碼我們可以看出
今天中午正在帶著耳機(jī)遨游在代碼的世界里,被運(yùn)營在群里
@
了,氣沖沖的反問我最近有刪生產(chǎn)的用戶數(shù)據(jù)的嗎?我肯定客氣的回答道沒有呀?生產(chǎn)的數(shù)據(jù)我怎么能隨隨便便可以刪除,這可是公司的紅線,再說了我也沒有數(shù)據(jù)庫的刪除權(quán)限啊,不過查詢權(quán)限還是有的。趕緊登上堡壘機(jī),然后去生產(chǎn)數(shù)據(jù)庫查一下數(shù)據(jù),查了一下數(shù)據(jù)是還在的,嚇?biāo)懒?,?shù)據(jù)還在問題就不大了,無非就是應(yīng)用程序出問題了,趕緊打開代碼查看下,為什么會(huì)少了一條用戶數(shù)據(jù),看了下代碼貌似沒啥問題就是比較簡單的一個(gè)邏輯,直接從DB
通過分頁查詢數(shù)據(jù)給到前端,然后前端負(fù)責(zé)展示,沒有啥復(fù)雜的邏輯。心想肯定是前端的問題,肯定是他少展示了數(shù)據(jù),立馬把問題也甩給了他,讓他幫忙配合一起看看是否是前端的問題,然后自己也仔細(xì)看看代碼,不到一分鐘前端說他展示的數(shù)據(jù)沒有問題,都是后端給到的,沒有漏掉展示的。那就是后端的bug
了羅。肉眼望去覺得可能出問題的就是分頁導(dǎo)致的數(shù)據(jù)丟了。不過這個(gè)分頁插件是全公司都在用,應(yīng)該不至于出問題吧,找不到問題只能讓測試幫忙在測試環(huán)境試試,看看是否可以復(fù)現(xiàn)。測試環(huán)境復(fù)現(xiàn)
仔細(xì)看了一眼,居然有個(gè)去重的方法,去重邏輯也比較簡單就是把list
通過轉(zhuǎn)為set去下重,看下來應(yīng)該就是這個(gè)去重方法有問題了
大致寫了單元測試模仿了下生產(chǎn)的數(shù)據(jù),大致邏輯如下:public?static?void?main(String[]?args)?{
????????Set?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;
????}
我們可以輸出結(jié)果set
集合的長度是1,user1
和user2
是相等的,明明兩個(gè)user
的ID
是不一樣的,為何會(huì)相等,我們知道set可以去重
是因?yàn)镾et的操作,都是通過操作map來實(shí)現(xiàn)的,set
的add
其實(shí)就是調(diào)用map
的put
方法,map
的put
方法我相信大家應(yīng)該都去看過其源碼,這里就不詳細(xì)再說了,大概流程就是通過key通過hash算法定位到數(shù)組的下標(biāo),先判斷key
的hash
是否相等,如果相等再去判斷key的value相等,如果都相等就會(huì)覆蓋原來的值。我們上面這個(gè)例子就是對象的hash
和value
都相等導(dǎo)致,但是我們的兩個(gè)對象user1
和user2
應(yīng)該是不等的,因?yàn)镮D不等,那為什么會(huì)相等列?我們仔細(xì)看下上面的代碼,我們使用了lombok
里面@Data
注解,我們可以看看這個(gè)注解幫我們生成了哪些方法

@Data
注解幫我們生成了 注在類上,提供類的get、set、equals、hashCode、canEqual、toString
方法,這個(gè)注解確實(shí)比較方便。上面那個(gè)bug
就是因?yàn)樗傻膃quals方法有問題,我們可以把上述代碼編譯下,然后把class
里面生成的equals
方法拷貝出來看看
equals
方法只比較了userName
這個(gè)字段,也就是當(dāng)前類的字段,并沒有去比較父類的字段,這就是導(dǎo)致兩個(gè)對象相等的原因,我們既然找到問題了,那解決問題就比較簡單。解決問題
- 手動(dòng)重寫
equals
和hashCode
方法,這種方法肯定是不推薦的,我們既然用了lombok
就是為了解放我們的雙手,是代碼變得更加簡潔。 - 在比較的類上加上
@EqualsAndHashCode(callSuper = true) callSuper = true
會(huì)包含父類的equals
和hashCode
方法 我們可以對比下加上@EqualsAndHashCode(callSuper = true)
和沒有加上這個(gè)注解生成的equals
方法的代碼差異。差異點(diǎn)還是很明顯的,加入了
@EqualsAndHashCode(callSuper = true)
會(huì)去調(diào)用父類的equals
方法比較,所以這個(gè)注解也能夠解決這個(gè)問題。 - 這樣加上注解確實(shí)可以解決問題,但是每個(gè)類上面都要加上這個(gè)注解,這也是個(gè)體力活。我們可以再找找其他的方案,例如有沒有比如配置文件設(shè)置下什么的,然后就能全局生效了。最終通過查詢資料發(fā)現(xiàn)我們我們寫一個(gè)
lombok.config
的配置文件放在我們項(xiàng)目的根目錄下面,內(nèi)容寫上lombok.equalsAndHashCode.callSuper = call
效果等同于@EqualsAndHashCode(callSuper = true)
,這樣的話我們就不需要為每個(gè)類都去加上這個(gè)注釋了,相當(dāng)于在這個(gè)項(xiàng)目下面只要用到了@Data
注解的類都會(huì)為其加上@EqualsAndHashCode(callSuper = true)
通過配置文件的方式就可以全局生效。
總結(jié)
- 我們再來回顧下上面的問題,歸根結(jié)底還是由于對象的
equals
方法使用不當(dāng)引起的,所以我們在如果在判斷自定義對象業(yè)務(wù)判斷相等的時(shí)候需要去重寫下hashCode
和equals
方法,重寫的時(shí)候我們可以通過idea
來生成,生成后最好還是去看一眼,看看生成的是否符合我們的業(yè)務(wù)要求。 - 我們在工作中操作一些常見的容器類比如Set、Map等來實(shí)現(xiàn)一些我們自己的業(yè)務(wù),我們還是有必要去看看它們的源碼的,就比如我們通過Set來進(jìn)行去重,如果我們是使用的自定義對象的話,如果沒有重寫
hashCode
和equals
方法的話,去重就會(huì)去不成功,我們只有了解了它,才能真正的去用好它。在關(guān)于hashCode
和equals
阿里巴巴開發(fā)手冊也有明確的說到 lombok
用起來還是挺爽的,但是還是有一些細(xì)節(jié)需要稍微注意下。使用前可以大概的去看看它的官網(wǎng)提供的內(nèi)容,不然出現(xiàn)莫名其妙的問題你都不知道如何下手。這個(gè)就有點(diǎn)類似于我們使用SpringBoot
一樣,用起來非常爽,但是如果遇到莫名其妙的bug
解決起來就比較頭疼。- 最后我們再來回顧幾道關(guān)于
hashCode
和equals
的比較常見的面試題?其實(shí)如果我們只要真正看過HashMap的源碼的話,這下面幾個(gè)面試題還是非常簡單的。什么情況下需要我們?nèi)ブ貙?方法?如果只重寫equals
方法不重寫HashCode
可以嗎?equals ,== 和hashcode()
的區(qū)別?