在目前衆多編程語言中,Java 語言的表現仍是搶眼,不管是企業級服務端開發,仍是 Andorid 客戶端開發,都是做爲開發語言的首選,甚至在大數據開發領域,Java 語言也能佔有一席之地,如 Hadoop,Spark,Flink 大數據等。而做爲已經誕生 24 年的 Java 相比其餘語言來講,編寫起來略顯得冗長和複雜,而爲了能極大提高 Java 開發的效率和代碼簡潔性,一個 Java 庫 Lombok 就這樣誕生了。java
首先咱們仍是看下 Lombok 官方的描述:git
Project Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java. Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.github
從上面的說明裏咱們能夠初步認識一下 Lombok,一個做用於編輯器和構建工具的 Java 庫,能夠對編寫的 Java 代碼進行加強,好比說不用再寫實體類的 getter
方法,equals
方法而是自動生成,自動生成日誌輸出變量等等,減小重複模板的代碼。大概知道了 Lombok 框架提供的功能後,接下來咱們就真正使用一下 Lombok 提供的註解,看它是如何幫助咱們提升書寫 Java 代碼的簡潔性和效率的。apache
本文主要內容涉及以下:編程
示例項目:github.com/wrcj12138aa…segmentfault
- lombok-actions:
環境支持:框架
- JDK 8
- SpringBoot 2.1.4
- Maven 3.6.0
使用 Lombok 以前咱們先要在所使用的 IDE 中進行集成安裝,這裏以 IDEA 爲例,安裝步驟十分簡單:eclipse
前往 File -> Settings -> Plugin -> Marketplace
,搜索 Lombok編程語言
選擇搜索結果 Lombok ,點擊 Install 安裝。編輯器
安裝完成後重啓便可。
基於 Eclipse 的 Lombok 插件安裝方法這裏就不詳細描述了,官方也給了對應的文檔說明:projectlombok.org/setup/eclip…
在 IDE 安裝了 Lombok 插件後,咱們就能夠在 pom.xml
文件中添加 Lombok 的依賴進行使用了。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
複製代碼
注意:
pom
依賴設置 scope 爲provided
,是爲了讓 Lombok 庫不被打包進程序。
一般咱們編寫實體類不管多少個字段,都要爲其提供 getter
和 setter
方法,以下面的示例類 User.java
咱們常會遇到這種狀況:某個實體類新增和修改某個字段,咱們都須要單獨處理調整,十分麻煩而且重複。這時候若是咱們使用 Lombok 提供 @Getter/@Setter
註解就能幫咱們省去 getter 和 setter
方法的維護,由 Lombok 對 User
類自動生成 getter
和 setter
方法,二者最終的字節碼時同樣的,而咱們如今在 User.java
上編寫的代碼僅僅 7 行便可:
@Getter
@Setter
public class User {
private Integer id;
private String username;
private String password;
}
複製代碼
而後用測試類 UserTests.java
測試結果以下:
public class UserTests {
@Test
public void test() {
User user = new User();
user.setUsername("one");
user.setPassword("zxc123");
Assert.assertEquals(user.getUsername(), "one");
Assert.assertEquals(user.getPassword(), "zxc123");
}
}
複製代碼
@Getter/@Setter
註解不只可使用在類上,還可使用在字段上,這樣就是表示針對該字段自動生成 getter /setter
方法。
@Getter
@Setter
private String password;
複製代碼
這裏該註解使用在類上,仍是在字段上的區別就是,若是註解使用在類上,只針對這個類的非靜態字段有效。
須要注意的一點是:若是 @Getter
註解修飾了 boolean
類型的變量,其生成的 getter
方法簽名是 isXXX
形式,而不是 getXXX
形式。
除此以外,@Getter/@Setter
還提供訪問權限控制的屬性 lombok.AccessLevel value()
, 默認爲 PUBLIC
,而其餘選值都是枚舉類型:MODULE, PROTECTED, PACKAGE, PRIVATE
顧名思義,@NonNull
用於標記類中不能容許爲 null
的字段或者參數上,任何使用該字段的地方都生成空指針判斷代碼,若@NonNull
標記的變量爲 null,拋出 NullPointException
(NPE) 異常。好比下面示例代碼:
public class User {
private Integer id;
private String username;
private String password;
public User(Integer id, @NonNull String username, @NonNull String password) {
this.id = id;
this.username = username;
this.password = password;
}
}
複製代碼
使用了 @NonNull
註解以後咱們能夠獲取到反編譯以後的字節碼信息以下,這就是 Lombok 給咱們生成的最終的代碼:
public class User {
private Integer id;
private String username;
private String password;
public User(Integer id, @NonNull String username, @NonNull String password) {
if (username == null) {
throw new NullPointerException("username is marked non-null but is null");
} else if (password == null) {
throw new NullPointerException("password is marked non-null but is null");
} else {
this.id = id;
this.username = username;
this.password = password;
}
}
}
複製代碼
再來看下平時常常會碰見的場景,爲實體類編寫構造器方法,Lombok 提供了三個不一樣構造器註解 @NoArgsConstructor / @AllArgsConstructor / @RequiredArgsConstructor
分別對用不一樣構造器方法處理方式,接下來就一一描述。
@NoArgsConstructor
爲實體類生成無參的構造器方法
@AllArgsConstructor
爲實體類生成除了static
修飾的字段以外帶有各參數的構造器方法。
@RequiredArgsConstructor
爲實體類生成指定字段的構造器方法,而這些字段須要被 final
,或者 @NonNull
修飾。
```java
@RequiredArgsConstructor
public class User3 {
private Integer id;
private final String username;
@NonNull
private String password;
}
```
複製代碼
編譯成功後使用構造器方法時就是這樣的效果:User3 user3 = new User3("user3", "zxc123");
@ToString
會給類自動生成易閱讀的 toString
方法,帶上有所非靜態字段的屬性名稱和值,這樣就十分便於咱們平常開發時進行的打印操做。
@Getter
@Setter
@AllArgsConstructor
@ToString
public class User2 {
private Integer id;
private String username;
private String password;
}
複製代碼
最終編譯成字節碼,反編譯結果以下:
public class User2 {
private Integer id;
private String username;
private String password;
// 省去 setter/getter
public String toString() {
return "User2(id=" + this.getId() + ", username=" + this.getUsername() + ", password=" + this.getPassword() + ")";
}
}
複製代碼
另外,註解 @ToString
還支持設置指定哪些字段的日誌化輸出,哪些不須要出如今 toString
方法中。使用屬性 @ToString.Exclude
排除不須要在 toString
中出現的字段,使用 @ToString.Include
標記須要出如今 toString
中的字段,具體用法可參見示例:
@Getter
@Setter
@AllArgsConstructor
@ToString
public class User2 {
@ToString.Exclude
private Integer id;
@ToString.Include
private String username;
@ToString.Include
private String password;
}
複製代碼
打印 User2
對象的日誌效果就是:User2(username=user2, password=zcx123)
。
@EqualsAndHashCode
註解就是用於根據類所擁有的非靜態字段自動重寫 equals
方法和 hashCode 方法,方便咱們用於對象間的比較。相似 @ToString
,@EqualsAndHashCode
還可使用須要做爲比較的字段和排除不須要比較的字段,具體用法能夠看以下示例:
@Getter
@Setter
@AllArgsConstructor
@ToString
@EqualsAndHashCode
public class User4 {
@EqualsAndHashCode.Exclude
private Integer id;
@EqualsAndHashCode.Include
private String username;
@EqualsAndHashCode.Exclude
private String password;
}
複製代碼
寫完實體類代碼,咱們編寫測試方法試下效果:
@Test
public void testEqual() {
User4 user4 = new User4(1, "user4", "zxc");
User4 user4_2 = new User4(1, "user4", "123");
Assert.assertEquals(user4, user4_2); // ture
}
複製代碼
@Data/@Value
註解,提供了更綜合的生成代碼功能,等價於下面幾個註解
@Getter
@Setter
@RequiredArgsConstructor
@ToString
@EqualsAndHashCode
複製代碼
兩個註解都只能使用在類上,與 @Data
不一樣, @Value
用來修飾不可變的類上。通常實體類沒有特別的限制的話,一般能夠直接使用 @Data
註解修飾。
@Builder
是一個很是強大的註解,提供了一種基於建造者模式的構建對象的 API。使用 @Builder
註解爲給咱們的實體類自動生成 builder()
方法,而且直接根據字段名稱方法進行字段賦值,最後使用 build()
方法構建出一個實體對象。
@Data
@Builder
public class User6 {
private Integer id;
private String username;
private String password;
}
@Test
public void testBuilder() {
User6 user6 = User6.builder().id(1).username("user6").password("zxc123").build();
log.warn("testLog: {}", user6); // User6(id=1, username=user6, password=zxc123)
}
複製代碼
須要注意的是 @Builder
不支持父類字段的生成,當一個實體類存在父類時,@Builder
只能生成當前類的字段構建方法。若須要用到父類的字段方法時, Lombok 提供了新的註解 @SuperBuilder
來應對這種狀況,下面是 @SuperBuilder
註解的使用方式:
@SuperBuilder
@Getter
@Setter
public class Parent {
private int id;
private String name;
}
@SuperBuilder
@Data
public class Child extends Parent {
private String childName;
}
複製代碼
調用示例:
Child child = Child.builder().id(1).name("父類名稱").childName("子類名稱").build();
System.out.println(child.getId());
複製代碼
因爲 Lombok Plugin 還未更新支持
@SuperBuilder
,因此以上寫法在 IDEA 下還會提示編譯錯誤,沒法找到builder()
方法。
也能夠參考此文方式去處理繼承的狀況:reinhard.codes/2015/09/16/…
正對程序類中常見不一樣框架 Logger 對象,Lombok 也提供了註解,來自動生成 Logger 對象,實現優雅地輸出日誌,只須要在類上使用日誌註解如 @Log
。固然 Lombok 支持了多個日誌框架,而且提供對應的註解以下:
@CommonsLog
等價效果: private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);
@Flogger
等價效果: private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass();
@JBosLog
等價效果: private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);
@Log
等價效果: private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
@Log4j
等價效果: private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);
@Log4j2
等價效果: private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
@Slf4j
等價效果: private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
@XSlf4j
等價效果: private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);
下面代碼使用 @Slf4j
註解進行日誌輸出:
@Slf4j
public class UserTests {
// ....
@Test
public void testLog() {
User5 user5 = new User5();
user5.setId(1);
user5.setUsername("user5");
user5.setPassword("zxc123");
log.warn("testLog: {}", user5);
// 21:57:15.488 [main] WARN com.one.learn.lombok.UserTests - testLog: User5(id=1, username=user5, password=zxc123)
}
}
複製代碼
@Cleanup
用於標記須要釋放清理操做的資源對象變量,如 FileInputStream
, FileOutputStream
等,標記以後資源對象使用完畢後,就會被自動關閉和清理,實際上這裏 Lombok 實現效果與 Java7 特性 try with resource
同樣, 爲咱們屏蔽了關閉資源的模板代碼,下面給出 @Cleanup
的使用示例:
public class CleanupExample {
public static void main(String[] args) throws IOException {
@Cleanup InputStream in = new FileInputStream(args[0]);
@Cleanup OutputStream out = new FileOutputStream(args[1]);
byte[] b = new byte[10000];
while (true) {
int r = in.read(b);
if (r == -1) {
break;
}
out.write(b, 0, r);
}
}
}
複製代碼
將 CleanupExample.java
編譯生成的字節碼反編譯能夠獲得以下結果:
public class CleanupExample {
//...
public static void main(String[] args) throws IOException {
FileInputStream in = new FileInputStream(args[0]);
try {
FileOutputStream out = new FileOutputStream(args[1]);
try {
byte[] b = new byte[10000];
while(true) {
int r = in.read(b);
if (r == -1) {
return;
}
out.write(b, 0, r);
}
} finally {
if (Collections.singletonList(out).get(0) != null) {
out.close();
}
}
} finally {
if (Collections.singletonList(in).get(0) != null) {
in.close();
}
}
}
}
複製代碼
@SneakyThrows
主要用於在沒有 throws
關鍵字的狀況下,隱蔽地拋出受檢查異常,爲咱們日常開發中須要異常拋出時省去的 throw
操做,下面爲使用 @SneakyThrows
的示例代碼:
public class SneakyThrowsExample implements Runnable {
@SneakyThrows(UnsupportedEncodingException.class)
public String utf8ToString(byte[] bytes) {
return new String(bytes, "UTF-8");
}
@SneakyThrows
public void run() {
throw new Throwable();
}
}
複製代碼
最終編譯成字節碼,反編譯結果以下:
public class SneakyThrowsExample implements Runnable {
public SneakyThrowsExample() {
}
public String utf8ToString(byte[] bytes) {
try {
return new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException var3) {
throw var3;
}
}
public void run() {
try {
throw new Throwable();
} catch (Throwable var2) {
throw var2;
}
}
}
複製代碼
val/var
用於局部變量的修飾,有了這注解修飾後,變量的類型就會自動經過等號右邊的表達式推斷出來,這個功能借鑑於許多編程語言的自動類型推斷的特性。 而 val
與 var
的區別在於, val
用於修飾不可變變量,var 修飾可變變量。當 val
修飾的變量被從新賦值時,編譯器就會提示異常:Error: java: 沒法爲最終變量 X 分配值
。實際用法也比較簡單,可參考下面代碼:
@Slf4j
public class VarValExample {
public static void main(String[] args) {
val text = "abc";
// text = "1"; // Error: java: 沒法爲最終變量 text 分配值`。
var num = 1;
num = 2;
log.info("text:{},num:{}", text, num); // text:abc,num:2
}
}
複製代碼
到這裏咱們學習了 Lombok 的近乎 80% 經常使用的註解,應用在咱們的平常開發中已是綽綽有餘了,開始嘗試 使用 Lombok 吧,慢慢地就會感覺下效率的提高以及代碼的優雅。
若是讀完以爲有收穫的話,歡迎點【好看】,點擊文章頭圖,掃碼關注【聞人的技術博客】😄😄😄。
Project Lombok: projectlombok.org/
Project Lombok: Reducing Java Boilerplate Code:stackabuse.com/project-lom…
Lombok 經常使用註解的使用總結:segmentfault.com/a/119000001…
Lombok @Builder with Inheritance: www.baeldung.com/lombok-buil…
Lombok’s @Builder annotation and inheritance: reinhard.codes/2015/09/16/…
Lombok:讓 JAVA 代碼更優雅:blog.didispace.com/java-lombok…
Lombok 簡介:mp.weixin.qq.com/s?__biz=MzI…