讓人又愛又恨的 Lombok,到底該不該用
點擊上方?果汁簡歷?,選擇“置頂公眾號”
優(yōu)質(zhì)文章,第一時間送達

這兩天關(guān)于 Lombok 的文章層出不窮,眾說紛紜,那么到底是該不該用呢?
先說利好
先說一下它可以做什么,最簡單的用法,幫助我們生成setter,getter,toString 和 equals 方法。如果我們不是用 Lombok 需要按照下面的方案寫什么內(nèi)容,我們也能看得出來這都是樣板代碼,沒啥實質(zhì)性
import?java.util.Objects;
public?class?User?{
????private?String?id;
????private?String?name;
????private?String?desc;
????public?String?getId()?{
????????return?id;
????}
????public?void?setId(String?id)?{
????????this.id?=?id;
????}
????public?String?getName()?{
????????return?name;
????}
????public?void?setName(String?name)?{
????????this.name?=?name;
????}
????public?String?getDesc()?{
????????return?desc;
????}
????public?void?setDesc(String?desc)?{
????????this.desc?=?desc;
????}
????@Override
????public?String?toString()?{
????????return?"User{"?+
????????????????"id='"?+?id?+?'\''?+
????????????????",?name='"?+?name?+?'\''?+
????????????????",?desc='"?+?desc?+?'\''?+
????????????????'}';
????}
????@Override
????public?boolean?equals(Object?o)?{
????????if?(this?==?o)?return?true;
????????if?(o?==?null?||?getClass()?!=?o.getClass())?return?false;
????????User?user?=?(User)?o;
????????return?Objects.equals(id,?user.id)?&&
????????????????Objects.equals(name,?user.name)?&&
????????????????Objects.equals(desc,?user.desc);
????}
????@Override
????public?int?hashCode()?{
????????return?Objects.hash(id,?name,?desc);
????}
}
那么我們?nèi)绻褂?Lombok 呢?引入依賴
<dependency>
??<groupId>org.projectlombokgroupId>
??<artifactId>lombokartifactId>
??<version>1.18.10version>
??<scope>providedscope>
dependency>
代碼
import?lombok.Data;
@Data
public?class?User?{
????private?String?id;
????private?String?name;
????private?String?desc;
}
就這樣就寫好了,是不是非常簡單?Lombok還提供了很多其他擴展的注解能力如下
@NonNull:用于做空指針異常檢測; @Cleanup:自動資源關(guān)閉,這個注解可以直接在流上面使用,@Cleanup InputStream inputStream = new FileInputStream(); @Getter/@Setter:自動生成get/set方法; @ToString:生成toString方法,方便打印調(diào)試; @EqualsAndHashCode:生成equals和hashCode方法,注意這兩個應(yīng)該同時去實現(xiàn); @NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor:構(gòu)造方法; @Data:相當(dāng)于 @ToString + @EqualsAndHashCode + @Getter + @Setter + @RequiredArgsConstructor。 @Builder:生成builder方法; @SneakyThrows:自動拋受檢異常,而無需顯式在方法上使用 throws 語句; @Synchronized:用在方法上,將方法聲明為同步的,并自動加鎖。 @Log:日志相關(guān),如果我們打了@XSlf4j,任何 class 都可以直接使用 log變量獲取到日志對象實例。
@CommonsLog:org.apache.commons.logging.LogFactory.getLog(LogExample.class);
@Flogger:com.google.common.flogger.FluentLogger.forEnclosingClass();
@JBossLog:org.jboss.logging.Logger.getLogger(LogExample.class);
@Log:java.util.logging.Logger.getLogger(LogExample.class.getName());
@Log4j:org.apache.log4j.Logger.getLogger(LogExample.class);
@Log4j2:org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
@Slf4j:org.slf4j.LoggerFactory.getLogger(LogExample.class);
@XSlf4j:org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);
@CustomLog:com.foo.your.LoggerFactory.createYourLogger(LogExample.class);
下面是一些比較難理解的注解實例,直接可以通過注釋查看用法,后面附上了 IDEA 反編譯的 class 便一目了然。
import?lombok.*;
import?java.io.FileInputStream;
import?java.io.InputStream;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public?class?User?{
????private?String?id;
????private?String?name;
????private?String?desc;
????public?static?void?main(String[]?args)?{
????????//?@NoArgsConstructor?生成
????????new?User();
????????//?@AllArgsConstructor?生成
????????new?User("juice-resume",?"果汁簡歷",?"專注于?Java?方向技術(shù)分享");
????????//?@Builder?生成
????????User?user?=?User.builder().id("juice-resume").name("果汁簡歷").desc("專注于?Java?方向技術(shù)分享").build();
????}
????//?@SneakyThrows?自動生成?throws?FileNotFoundException
????@SneakyThrows
????private?void?read()?{
????????//?@Cleanup?相當(dāng)于?inputStream.close();
????????@Cleanup
????????InputStream?inputStream?=?new?FileInputStream("");
????}
????/**
?????*?@Synchronized?private?final?Object?$lock?=?new?Object[0];
?????*?public?void?write()?{
?????*??????synchronized(this.$lock)?{
?????*??????????System.out.println("write");
?????*??????}
?????*?}
?????*/
????@Synchronized
????public?void?write()?{
????????System.out.println("write");
????}
}
IDEA 反編譯的 class 文件
import?java.io.FileInputStream;
import?java.io.InputStream;
import?java.util.Collections;
public?class?User?{
????private?final?Object?$lock?=?new?Object[0];
????private?String?id;
????private?String?name;
????private?String?desc;
????public?static?void?main(String[]?args)?{
????????new?User();
????????new?User("juice-resume",?"果汁簡歷",?"專注于?Java?方向技術(shù)分享");
????????User?user?=?builder().id("juice-resume").name("果汁簡歷").desc("專注于?Java?方向技術(shù)分享").build();
????}
????private?void?read()?{
????????try?{
????????????InputStream?inputStream?=?new?FileInputStream("");
????????????if?(Collections.singletonList(inputStream).get(0)?!=?null)?{
????????????????inputStream.close();
????????????}
????????}?catch?(Throwable?var2)?{
????????????throw?var2;
????????}
????}
????public?void?write()?{
????????synchronized(this.$lock)?{
????????????System.out.println("write");
????????}
????}
????public?static?User.UserBuilder?builder()?{
????????return?new?User.UserBuilder();
????}
????public?String?getId()?{
????????return?this.id;
????}
????public?String?getName()?{
????????return?this.name;
????}
????public?String?getDesc()?{
????????return?this.desc;
????}
????public?void?setId(final?String?id)?{
????????this.id?=?id;
????}
????public?void?setName(final?String?name)?{
????????this.name?=?name;
????}
????public?void?setDesc(final?String?desc)?{
????????this.desc?=?desc;
????}
????public?boolean?equals(final?Object?o)?{
????????if?(o?==?this)?{
????????????return?true;
????????}?else?if?(!(o?instanceof?User))?{
????????????return?false;
????????}?else?{
????????????User?other?=?(User)o;
????????????if?(!other.canEqual(this))?{
????????????????return?false;
????????????}?else?{
????????????????label47:?{
????????????????????Object?this$id?=?this.getId();
????????????????????Object?other$id?=?other.getId();
????????????????????if?(this$id?==?null)?{
????????????????????????if?(other$id?==?null)?{
????????????????????????????break?label47;
????????????????????????}
????????????????????}?else?if?(this$id.equals(other$id))?{
????????????????????????break?label47;
????????????????????}
????????????????????return?false;
????????????????}
????????????????Object?this$name?=?this.getName();
????????????????Object?other$name?=?other.getName();
????????????????if?(this$name?==?null)?{
????????????????????if?(other$name?!=?null)?{
????????????????????????return?false;
????????????????????}
????????????????}?else?if?(!this$name.equals(other$name))?{
????????????????????return?false;
????????????????}
????????????????Object?this$desc?=?this.getDesc();
????????????????Object?other$desc?=?other.getDesc();
????????????????if?(this$desc?==?null)?{
????????????????????if?(other$desc?!=?null)?{
????????????????????????return?false;
????????????????????}
????????????????}?else?if?(!this$desc.equals(other$desc))?{
????????????????????return?false;
????????????????}
????????????????return?true;
????????????}
????????}
????}
????protected?boolean?canEqual(final?Object?other)?{
????????return?other?instanceof?User;
????}
????public?int?hashCode()?{
????????int?PRIME?=?true;
????????int?result?=?1;
????????Object?$id?=?this.getId();
????????int?result?=?result?*?59?+?($id?==?null???43?:?$id.hashCode());
????????Object?$name?=?this.getName();
????????result?=?result?*?59?+?($name?==?null???43?:?$name.hashCode());
????????Object?$desc?=?this.getDesc();
????????result?=?result?*?59?+?($desc?==?null???43?:?$desc.hashCode());
????????return?result;
????}
????public?String?toString()?{
????????return?"User(id="?+?this.getId()?+?",?name="?+?this.getName()?+?",?desc="?+?this.getDesc()?+?")";
????}
????public?User()?{
????}
????public?User(final?String?id,?final?String?name,?final?String?desc)?{
????????this.id?=?id;
????????this.name?=?name;
????????this.desc?=?desc;
????}
????public?static?class?UserBuilder?{
????????private?String?id;
????????private?String?name;
????????private?String?desc;
????????UserBuilder()?{
????????}
????????public?User.UserBuilder?id(final?String?id)?{
????????????this.id?=?id;
????????????return?this;
????????}
????????public?User.UserBuilder?name(final?String?name)?{
????????????this.name?=?name;
????????????return?this;
????????}
????????public?User.UserBuilder?desc(final?String?desc)?{
????????????this.desc?=?desc;
????????????return?this;
????????}
????????public?User?build()?{
????????????return?new?User(this.id,?this.name,?this.desc);
????????}
????????public?String?toString()?{
????????????return?"User.UserBuilder(id="?+?this.id?+?",?name="?+?this.name?+?",?desc="?+?this.desc?+?")";
????????}
????}
}
好了,說了這么多該總結(jié)了,Lombok確實能給我們帶來極大的便利,減少大量重復(fù)、無業(yè)務(wù)邏輯的代碼,提高開發(fā)效率,那么它由什么缺點呢?更多IDEA相關(guān)技術(shù)可以關(guān)注微信訂閱號果汁簡歷回復(fù)IDEA獲取。
再說弊端
1. IDE 依賴
上文中引入的 pom.xml 的依賴只是在 maven 編譯的時候有作用,如果使用 IDEA,本身也需要安裝插件,這樣對于新拉取代碼的同學(xué)無疑是一項額外的配置,當(dāng)然私以為就像是安裝 JDK 一樣,這個操作并不繁瑣。

2. JDK版本兼容
當(dāng)我想要將現(xiàn)有項目的JDK從Java 8升級到Java 11時,Lombok 會存在不兼容的問題,不過反過來講,這并不是一個致命問題,線上 run 的很好的項目,會那么輕易的就切換 JDK 版本么?如果是針對新的項目,自然有更多的選擇。JDK 并沒有萬不得已要升級的原因,如果真的有也可以用 Delombok 完成。
3. 調(diào)試?yán)щy
很多讀者反饋,因為沒有源碼 debug 困難,不過對于貧血模型來說,debug setter,getter,toString 和 equals 方法的機會也太少了吧,倘若你選擇的是充血模型,那么自然也不會選擇 Lombok了。
孰輕孰重
通看利弊以后我們發(fā)現(xiàn),好的地方很明顯,就是效率,同時也伴隨一些問題,但是倒不是不能接受,依賴、兼容、調(diào)試、可讀性其實相對于效率來說都略顯單薄,所以小編倒是推薦使用 Lombok,從效率角度出發(fā),把它僅僅當(dāng)做一個提效的工具,并不是爭相談?wù)摰脑掝}。當(dāng)然看下下面的圖, Lombok 既然能在 Top Downloads 位居第 6 名也不是刷出來的啦。


3.?大型網(wǎng)站架構(gòu)演化發(fā)展歷程
8. 深入理解 MySQL:快速學(xué)會分析SQL執(zhí)行效率

掃碼二維碼關(guān)注我
·end·
—如果本文有幫助,請分享到朋友圈吧—
我們一起愉快的玩耍!

