新來的同事不會用 Lombok,所以會引發本文!
背景
最近公司新來一個高 Java 的同事,搞了半天項目還沒有跑起來,後來叫我過去幫他看一下,然後指着紅色的編譯錯誤和我說是不是代碼有問題。。
我頓時就心想,這人是不是太水了啊,工作三年了,簡單的編譯問題都搞不定?但是當我認真看了錯誤之後,發現……他竟然沒裝 Lombok 插件……
然後我和他說出了問題所在,讓他安裝下 Lombok 插件再重新編譯下,他居然和我說不知道什麼插件,感覺他沒用過吧,甚至都沒有聽說過。
好吧,我認了,我默默親自爲他把 Lombok 裝上了!
如果你沒用過,我也不覺得奇怪,Lombok 畢竟是團隊工具,但如果你也沒聽過,那就感覺獲取新知識自我提升學習的能力有點弱了。
當然,本篇不是教你怎麼用 Lombok,因爲我之前就已經寫過教程分享過了,不會的可以點擊這個鏈接看下,還熱乎着呢。
放棄 Lombok?
因爲,最近也有看到一些公衆號在發放棄 Lombok 的文章,再結合最近一個新同事的情況,也談談到底要不要用 Lombok。
一味地讓大家放棄,我感覺有點偏激了,任何事物,存在就即合理,關鍵是利弊權衡的問題罷了。
用不用 Lombok,又是分兩派,公說公有理,婆說婆有理,仁者見仁,智者見智,誰也說服不了誰,類似 Eclipse 和 IntelliJ IDEA 誰更好用之爭!
我想說,爭這些沒任何意義,這完全取決於團隊的決策,取決於你的團隊能不能 Hold 住這個東西,如果利 > 弊,用它就對了,如果弊 > 利,那就考慮放棄吧。
如果你是個人項目,請大膽用吧!
Lombok 的弊端
Lombok 的好處就不說了,就是幫我們大量簡化代碼,這裏重點說下爲什麼有人不推薦使用 Lombok。
一、需要額外的組件
使用 Lombok 需要兩個必要的組件:
1)Lombok 依賴包
使用 Lombok 的註解,就必須引用它的依賴,最後編譯成最終的 class 類,如 Maven 依賴示例:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
這個不會引起問題,因爲它是代碼的一部分,而且在項目一開始的時候就引入進去了。
2)Lombok IDE 插件
Eclipse/ IntelliJ IDEA 都提供了 Lombok 插件,用來識別 Lombok 的註解,否則會顯示編譯報錯。
IntelliJ IDEA 插件示例:
如果某一個人爲了方便自己而使用,其他人不願意使用或者被迫使用,將導致團隊其他成員代碼沒法正常編譯,這也是問題的關鍵所在。
還有就是文章之前說的,來了一個新同事,如果他沒有相應的使用經驗,就需要額外的指導,對於老員工來說無疑也是一個額外的工作量。
二、@Data 註解的坑
@Data 註解用在類上,等同於下面這幾個註解合集:
@Getter, @Setter, @ToString 很簡單,用起來也沒問題,而 @RequiredArgsConstructor和 @EqualsAndHashCode 需要注意下。
1)RequiredArgsConstructor
Generates a constructor with required arguments.Required arguments are final fields and fields with constraints such as {@code @NonNull}.
即生成一個類構造器,參數包含所有用 final 修飾、以及 @NonNull 註解修飾的變量。
如果參數很多,都在一個構造器裏面,一、極不優雅,可讀性很差,二、不良設計。
與這個註解相關的還有 AllArgsConstructor 註解,包括所有參數,還是小心爲妙。但在參數不多的時候還是可以代替使用的,但對不熟悉的人來說就是個潛在的問題。
2)@EqualsAndHashCode
Generates implementations for the {@code equals} and {@code hashCode} methods inherited by all objects, based on relevant fields.
這個註解用來生成 equals 和 hashCode 方法,裏面有一個 callSuper() 方法:
/**
* Call on the superclass's implementations of {@code equals} and {@code hashCode} before calculating for the fields in this class.
* <strong>default: false</strong>
*
* @return Whether to call the superclass's {@code equals} implementation as part of the generated equals algorithm.
*/
boolean callSuper() default false;
是否調用父類的 equals 和 hashCode 方法,默認爲:false 不調用,這也是引起問題的關鍵。
來看下面的例子:
@Data
public class BaseStudent {
private int id;
}
@Data
@AllArgsConstructor
public class Student extends BaseStudent {
private String name;
private int age;
private String address;
}
把生成的 equals 和 hashCode 方法反編譯出來看下:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Student))
return false;
Student other = (Student)o;
if (!other.canEqual(this))
return false;
Object this$name = getName(), other$name = other.getName();
if ((this$name == null) ? (other$name != null) : !this$name.equals(other$name))
return false;
if (getAge() != other.getAge())
return false;
Object this$address = getAddress(), other$address = other.getAddress();
return !((this$address == null) ? (other$address != null) : !this$address.equals(other$address));
}
public int hashCode() {
int PRIME = 59;
result = 1;
Object $name = getName();
result = result * 59 + (($name == null) ? 43 : $name.hashCode());
result = result * 59 + getAge();
Object $address = getAddress();
return result * 59 + (($address == null) ? 43 : $address.hashCode());
}
最後判斷如果不是同一個對象時,會判斷每個變量的值,但是此時父類的值不參與比較,這顯然是不符合邏輯的,另外 hashCode 方法父類的值也沒有參與運算,也是潛在問題。
三、代碼跟蹤調試
使用 Lombok 可以幫助我們少寫很多代碼,但同時也降低了代碼可讀性和跟蹤、調試的問題。
比如,我想查找 getName() 方法都被哪些地方引用了,就不能直接按快捷鍵了,可能需要費一翻力氣。
代碼調試也有問題,比如我跟進 getAddress 方法,雖然進不去該方法,但可以直接跳到對應的變量,顯示對應的值。
但是我想調試生成後的 hashCode 方法的運算過程,代碼沒有,斷點都沒法打,怎麼調試?
即使如此,我覺得這個問題不大,我們很少去跟蹤這些代碼,我們也可以通過其他方式來曲線解決。
總結
以上一些問題都是使用 Lombok 不可避免的,這還只是已知的問題,未知的呢?
Lombok 雖好,你也要遵循團隊的規範,能用的情況下再用,也不能亂用,不瞭解其構造,亂用就容易出現問題的。
最好的方法是,作用域最小化,需要什麼就用什麼,註解單獨使用,而不是三七二十一什麼類上來都來一個 @Data 什麼的,出問題就欲哭無淚了。
所有種種潛在的問題都是領導者不願意看到的,所以,有的公司是明令禁止使用 Lombok的,我個人是不沾邊,適度運用就好,但不要過度依賴。
如果你還遇到其他使用 Lombok 的問題,歡迎留言分享~
-
@Getter
-
@Setter
-
@RequiredArgsConstructor
-
@ToString
-
@EqualsAndHashCode