Lombok 簡介

Lombok 簡介

點擊左上角,關注:「鍋外的大佬」設計模式

專一分享國外最新技術內容
幫助每位開發者更優秀地成長
和其餘語言相比, Java常常由於沒必要要的冗長被批評。 Lombok提供了一系列註解用以在後臺生成模板代碼,將其從你的類中刪除,從而有助於保持你的代碼整潔。較少的模板意味着更簡潔的代碼,更易於閱讀和維護。在本文中,我將涉及我常用的 Lombok功能,並想你展現如何使用他們生產更清晰、更簡潔的代碼。安全

1.局部變量類型推斷:val 和 var

許多語言經過查看等號右側的表達式來推斷局部變量類型。儘管如今 Java10+已經支持這種功能,但在以前的版本中沒有 Lombok的幫助就沒法實現。下面的代碼段展現瞭如何顯式指定局部類型:框架

final

Map
<
String
,

Integer
>
 map 
=

new

HashMap
<>();
map
.
put
(
"Joe"
,

21
);

在 Lombok中,咱們能夠經過使用 val來縮短它,以下所示:ide

val valMap 
=

new

HashMap
<
String
,

Integer
>();
valMap
.
put
(
"Sam"
,

30
);

注意, val在背後建立了一個 final且不可變的變量。若是你須要一個可變本地變量,可使用 var。函數

2.@NonNull

對方法參數進行 null檢查一般不是一個壞主意,特別是若是該方法造成的 API被其餘開發者使用。雖然這些檢查很簡單,可是他們可能變得冗長,特別是當你有多個參數時。以下所示,額外的代碼無助於可讀性,而且可能從方法的主要目的分散注意力。ui

public

void
 nonNullDemo
(
Employee
 employee
,

Account
 account
)

{

if
(
employee 
==

null
)

{

throw

new

IllegalArgumentException
(
"Employee is marked @NonNull but is null"
);

}

if
(
account 
==

null
)

{

throw

new

IllegalArgumentException
(
"Account is marked @NonNull but is null"
);

}

// do stuff
}

理想狀況下,你須要 null檢查——沒有干擾的那種。這就是 @NonNull發揮做用的地方。經過用 @NonNull標記參數, Lombok替你爲該參數生成 null檢查。你的方法忽然變得更加簡潔,但沒有丟失那些安全性的 null檢查。this

public

void
 nonNullDemo
(
@NonNull

Employee
 employee
,

@NonNull

Account
 account
)

{

// just do stuff
}

默認狀況下, Lombok會拋出 NullPointerException,若是你願意,能夠配置 Lombok拋出 IllegalArgumentException。我我的更喜歡 IllegalArgumentException,由於我認爲它更適合於對參數檢查。debug

3.更簡潔的數據類

數據類是 Lombok真正有助於減小模板代碼的領域。在查看該選項前,思考一下咱們常常須要處理的模板種類。數據類一般包括如下一種或所有:設計

  • 構造函數(有或沒有參數)
  • 私有成員變量的 getter 方法
  • 私有非 final 成員變量的 setter 方法
  • 幫助記錄日誌的 toString 方法
  • equals 和 hashCode(處理相等/集合)
    能夠經過 IDE 生成以上內容,所以問題不在於編寫他們花費的時間。問題是帶有少許成員變量的簡單類很快會變得很是冗長。讓咱們看看 Lombok如何經過處理上述的每一項來減小混亂。

3.1. @Getter 和 @Setter

想一想下面的 Car類。當生成 getter和 setter時,咱們會獲得接近 50 行代碼來描述一個包含 5 個成員變量的類。日誌

public

class

Car

{

private

String
 make
;

private

String
 model
;

private

String
 bodyType
;

private

int
 yearOfManufacture
;

private

int
 cubicCapacity
;

public

String
 getMake
()

{

return
 make
;

}

public

void
 setMake
(
String
 make
)

{

this
.
make 
=
 make
;

}

public

String
 getModel
()

{

return
 model
;

}

public

void
 setModel
(
String
 model
)

{

this
.
model 
=
 model
;

}

public

String
 getBodyType
()

{

return
 bodyType
;

}

public

void
 setBodyType
(
String
 bodyType
)

{

this
.
bodyType 
=
 bodyType
;

}

public

int
 getYearOfManufacture
()

{

return
 yearOfManufacture
;

}

public

void
 setYearOfManufacture
(
int
 yearOfManufacture
)

{

this
.
yearOfManufacture 
=
 yearOfManufacture
;

}

public

int
 getCubicCapacity
()

{

return
 cubicCapacity
;

}

public

void
 setCubicCapacity
(
int
 cubicCapacity
)

{

this
.
cubicCapacity 
=
 cubicCapacity
;

}

}

Lombok能夠替你生成 getter和 setter模板。經過對每一個成員變量使用 @Getter和 @Setter註解,你最終獲得一個等效的類,以下所示:

public

class

Car

{

@Getter

@Setter

private

String
 make
;

@Getter

@Setter

private

String
 model
;

@Getter

@Setter

private

String
 bodyType
;

@Getter

@Setter

private

int
 yearOfManufacture
;

@Getter

@Setter

private

int
 cubicCapacity
;
}

注意,你能夠在非 final成員變量上只使用 @Setter。在 final成員變量上使用它將致使編譯錯誤。

若是你須要爲每一個成員變量生成 getter和 setter,你也能夠在類級別使用 @Getter和 @Setter,以下所示。

@Getter

@Setter
public

class

Car

{

private

String
 make
;

private

String
 model
;

private

String
 bodyType
;

private

int
 yearOfManufacture
;

private

int
 cubicCapacity
;
}

3.2. @AllArgsConstructor

數據類一般包含一個構造函數,它爲每一個成員變量接受參數。IDE 爲 Car生成的構造函數以下所示:

public

class

Car

{

@Getter

@Setter

private

String
 make
;

@Getter

@Setter

private

String
 model
;

@Getter

@Setter

private

String
 bodyType
;

@Getter

@Setter

private

int
 yearOfManufacture
;

@Getter

@Setter

private

int
 cubicCapacity
;

public

Car
(
String
 make
,

String
 model
,

String
 bodyType
,

int
 yearOfManufacture
,

int
 cubicCapacity
)

{

super
();

this
.
make 
=
 make
;

this
.
model 
=
 model
;

this
.
bodyType 
=
 bodyType
;

this
.
yearOfManufacture 
=
 yearOfManufacture
;

this
.
cubicCapacity 
=
 cubicCapacity
;

}
}

咱們可使用 @AllArgsConstructor註解實現一樣功能。 @Getter和 @Setter、 @AllArgsConstructor減小模板,保持類更乾淨且更簡潔。

@AllArgsConstructor
public

class

Car

{

@Getter

@Setter

private

String
 make
;

@Getter

@Setter

private

String
 model
;

@Getter

@Setter

private

String
 bodyType
;

@Getter

@Setter

private

int
 yearOfManufacture
;

@Getter

@Setter

private

int
 cubicCapacity
;
}

還有其餘選項用於生成構造函數。 @RequiredArgsConstructor將建立帶有每一個 final成員變量參數的構造函數, @NoArgsConstructor將建立沒有參數的構造函數。

3.3. @ToString

在你的數據類上覆蓋 toString方法是有助於記錄日誌的良好實踐。IDE 爲 Car類生成的 toString方法以下所示:

@AllArgsConstructor
public

class

Car

{

@Getter

@Setter

private

String
 make
;

@Getter

@Setter

private

String
 model
;

@Getter

@Setter

private

String
 bodyType
;

@Getter

@Setter

private

int
 yearOfManufacture
;

@Getter

@Setter

private

int
 cubicCapacity
;

@Override

public

String
 toString
()

{

return

"Car [make="

+
 make 
+

", model="

+
 model 
+

", bodyType="

+
 bodyType 
+

", yearOfManufacture="

+
 yearOfManufacture 
+

", cubicCapacity="

+
 cubicCapacity 
+

"]"
;

}
}

咱們可使用 ToString註解廢除這個,以下所示:

@ToString
@AllArgsConstructor
public

class

Car

{

@Getter

@Setter

private

String
 make
;

@Getter

@Setter

private

String
 model
;

@Getter

@Setter

private

String
 bodyType
;

@Getter

@Setter

private

int
 yearOfManufacture
;

@Getter

@Setter

private

int
 cubicCapacity
;
}

默認狀況下, Lombok生成包含全部成員變量的 toString方法。能夠經過 exclude屬性 @ToString(exclude={"someField"},"someOtherField"}) 覆蓋行爲將某些成員變量排除。

3.4. @EqualsAndHashCode

若是你正在將你的數據類和任何類型的對象比較,則須要覆蓋 equals和 hashCode 方法。對象的相等是基於業務規則定義的。舉個例子,在 Car類中,若是兩個對象有相同的 make、 model和 bodyType,我可能認爲他們是相等的。若是我使用 IDE 生成 equals方法檢查 make、 model和 bodyType,它看起來會是這樣:

@Override
public

boolean
 equals
(
Object
 obj
)

{

if

(
this

==
 obj
)

return

true
;

if

(
obj 
==

null
)

return

false
;

if

(
getClass
()

!=
 obj
.
getClass
())

return

false
;

Car
 other 
=

(
Car
)
 obj
;

if

(
bodyType 
==

null
)

{

if

(
other
.
bodyType 
!=

null
)

return

false
;

}

else

if

(!
bodyType
.
equals
(
other
.
bodyType
))

return

false
;

if

(
make 
==

null
)

{

if

(
other
.
make 
!=

null
)

return

false
;

}

else

if

(!
make
.
equals
(
other
.
make
))

return

false
;

if

(
model 
==

null
)

{

if

(
other
.
model 
!=

null
)

return

false
;

}

else

if

(!
model
.
equals
(
other
.
model
))

return

false
;

return

true
;
}

等價的 hashCode實現以下所示:

@Override
public

int
 hashCode
()

{

final

int
 prime 
=

31
;

int
 result 
=

1
;
    result 
=
 prime 
*
 result 
+

((
bodyType 
==

null
)

?

0

:
 bodyType
.
hashCode
());
    result 
=
 prime 
*
 result 
+

((
make 
==

null
)

?

0

:
 make
.
hashCode
());
    result 
=
 prime 
*
 result 
+

((
model 
==

null
)

?

0

:
 model
.
hashCode
());

return
 result
;
}

雖然 IDE 處理了繁重的工做,但咱們在類中仍然有大量的模板代碼。 Lombok容許咱們使用 @EqualsAndHashCode類註解實現相同的功能,以下所示:

@ToString
@AllArgsConstructor
@EqualsAndHashCode
(
exclude 
=

{

"yearOfManufacture"
,

"cubicCapacity"

})
public

class

Car

{

@Getter

@Setter

private

String
 make
;

@Getter

@Setter

private

String
 model
;

@Getter

@Setter

private

String
 bodyType
;

@Getter

@Setter

private

int
 yearOfManufacture
;

@Getter

@Setter

private

int
 cubicCapacity
;
}

默認狀況下, @EqualsAndHashCode會建立包含全部成員變量的 equals和 hashCode方法。 exclude選項可用於通知 Lombok排除某些成員變量。在上面的代碼片斷中。我已經從生成的 equals和 hashCode方法中排除了 yearOfManuFacture 和 cubicCapacity。

3.5. @Data

若是你想使數據類儘量精簡,可使用 @Data註解。 @Data 是 @Getter、 @Setter、 @ToString、 @EqualsAndHashCode 和 @RequiredArgsConstructor 的快捷方式。

@ToString
@RequiredArgsConstructor
@EqualsAndHashCode
(
exclude 
=

{

"yearOfManufacture"
,

"cubicCapacity"

})
public

class

Car

{

@Getter

@Setter

private

String
 make
;

@Getter

@Setter

private

String
 model
;

@Getter

@Setter

private

String
 bodyType
;

@Getter

@Setter

private

int
 yearOfManufacture
;

@Getter

@Setter

private

int
 cubicCapacity
;

}

經過使用 @Data,咱們能夠將上面的類精簡以下:

@Data
public

class

Car

{

private

String
 make
;

private

String
 model
;

private

String
 bodyType
;

private

int
 yearOfManufacture
;

private

int
 cubicCapacity
;

}

4. 使用 @Buidler 建立對象

建造者設計模式描述了一種靈活的建立對象的方式。 Lombok能夠幫你輕鬆的實現該模式。看一個使用簡單 Car類的示例。假設咱們但願能夠建立各類 Car對象,但咱們但願在建立時設置的屬性具備靈活性。

@AllArgsConstructor
public

class

Car

{

private

String
 make
;

private

String
 model
;

private

String
 bodyType
;

private

int
 yearOfManufacture
;

private

int
 cubicCapacity
;

private

List
<
LocalDate
>
 serviceDate
;
}

假設咱們要建立一個 Car,但只想設置 make和 model。在 Car上使用標準的全參數構造函數意味着咱們只提供 make和 model並設置其餘參數爲 null。

Car2
 car2 
=

new

Car2
(
"Ford"
,

"Mustang"
,

null
,

null
,

null
,

null
);

這可行但並不理想,咱們必須爲咱們不感興趣的參數傳遞 null。咱們能夠建立一個只接受 make和 model的構造函數來避開這個問題。這是一個合理的解決方法,但不夠靈活。若是咱們有許多不一樣的字段排列,咱們能夠用什麼來建立一個新 Car?最終咱們獲得了一堆不一樣的構造函數,表明了咱們能夠實例化 Car的全部可能方式。

解決該問題的一種乾淨、靈活的方式是使用建造者模式。 Lombok經過 @Builder 註解幫你實現建造者模式。當你使用 @Builder註解 Car類時, Lombok會執行如下操做:

  • 添加一個私有構造函數到 Car
  • 建立一個靜態的 CarBuilder類
  • 在 CarBuilder中爲 Car中的每一個成員建立一個 setter風格方法。
  • 在 CarBuilder中添加建立 Car的新實例的建造方法。
    CarBuilder上的每一個 setter風格方法返回自身的實例( CarBuilder)。這容許你進行方法鏈式調用併爲對象建立提供流暢的 API。讓咱們看看它如何使用。
Car
 muscleCar 
=

Car
.
builder
().
make
(
"Ford"
)

.
model
(
"mustang"
)

.
bodyType
(
"coupe"
)

.
build
();

如今只使用 make和 model建立 Car比以前更簡潔了。只需在 Car上簡單的調用生成的 builder方法獲取 CarBuilder實例,而後調用任何咱們感興趣的 setter風格方法。最後,調用 build建立 Car的新實例。

另外一個值得一提的方便的註解是 @Singular。默認狀況下,Lombok 爲集合建立使用集合參數的標準的 setter 風格方法。在下面的例子中,咱們建立了新的 Car並設置了服務日期列表。

Car
 muscleCar 
=

Car
.
builder
().
make
(
"Ford"
)

.
model
(
"mustang"
)

.
serviceDate
(
Arrays
.
asList
(
LocalDate
.
of
(
2016
,

5
,

4
)))

.
build
();

向集合成員變量添加 @Singular將提供一個額外的方法,容許你向集合添加單個項。

@Builder
public

class

Car

{

private

String
 make
;

private

String
 model
;

private

String
 bodyType
;

private

int
 yearOfManufacture
;

private

int
 cubicCapacity
;

@Singular

private

List
<
LocalDate
>
 serviceDate
;
}

如今咱們能夠添加單個服務日期,以下所示:

Car
 muscleCar3 
=

Car
.
builder
()

.
make
(
"Ford"
)

.
model
(
"mustang"
)

.
serviceDate
(
LocalDate
.
of
(
2016
,

5
,

4
))

.
build
();

這是一個有助於在建立對象期間處理集合時保持代碼簡潔的快捷方法。

5.日誌

Lombok另外一個偉大的功能是日誌記錄器。若是沒有 Lombok,要實例化標準的 SLF4J日誌記錄器,一般會有如下內容:

public

class

SomeService

{

private

static

final
 org
.
slf4j
.
Logger
 log 
=
 org
.
slf4j
.
LoggerFactory
.
getLogger
(
LogExample
.
class
);

public

void
 doStuff
(){

        log
.
debug
(
"doing stuff...."
);

}
}

這些日誌記錄器很沉重,併爲每一個須要日誌記錄的類添加了沒必要要的混亂。值得慶幸的是 Lombok提供了一個爲你建立日誌記錄器的註解。你要作的全部事情就是在類上添加註解,這樣就能夠了。

@Slf4j
public

class

SomeService

{

public

void
 doStuff
(){

        log
.
debug
(
"doing stuff...."
);

}
}

我在這裏使用了 @SLF4J註解,但 Lombok能爲幾乎全部通用 Java日誌框架生成日誌記錄器。有關更多日誌記錄器的選項,請參閱文檔。

6.Lombok給你控制權

我很是喜歡 Lombok的一點是它的不侵入性。。若是你決定在使用如 @Getter、 @Setter 或 @ToString時也想要本身的方法實現,你的方法將老是優先於 Lombok。它容許你在大多數時間使用 Lombok,但在你須要的時候仍有控制權。

7.寫得更少,作得更多

在過去的 4 到 5 年裏,我幾乎在每一個項目中都使用了 Lombok。我喜歡它,由於它減小了雜亂,最終獲得了更乾淨、更簡潔、更易閱讀的代碼。它不必定爲你節省大量時間,由於它生成的代碼能夠由 IDE 自動生成。話雖如此,我認爲更乾淨的代碼的好處不只僅是將其添加到 Java堆棧中。

8. 延展閱讀

我已經介紹了我常用的 Lombok功能,但還有不少我沒有講到。若是你喜歡目前爲止所看到的,並但願瞭解更多,請繼續閱讀 Lombok 文檔。

原文連接:https://dzone.com/articles/introduction-to-lombok

做者:Brian Hannaway

譯者:Darren Luo

推薦閱讀:避免在Java中檢查Null語句上篇好文:Spring Boot實現帶STOMP的WebSocket

相關文章
相關標籤/搜索