lombok想必已經有不少人已經使用了很長時間了,而我倒是第一次接觸到,有點呆。lombok主要是用於減小重複代碼,經過一組簡單的註釋取代一些重複的Java代碼。對於lombok的評價褒貶不一,有的人以爲特別方便,有的人以爲改變了一成不變的代碼結構,增長了代碼維護成本(有的人沒有用過lombok),我是以爲每個工具誕生確定是有他誕生的價值的,多學一個是一個啊,小老弟,用不用再說。:)html
官方文檔地址git
官方API地址github
官方註解介紹地址web
我這裏已經安裝好了,沒有安裝的時候按鈕應該是Installapi
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
<scope>provided</scope>
</dependency>複製代碼
顧名思義,生成get和set方法的註解,@Getter和@Setter發生在編譯階段,編譯以後,@Getter和@Setter相關的註解就消失了,取而代之的是相應的get和set方法。maven
public class LombokTest {
@Getter @Setter
private boolean flag;
}複製代碼
lombok遵循了boolean類型的get方法的約定,咱們來看一下編譯後的代碼(等效Java代碼)吧。ide
public class LombokTest {
private boolean flag;
public LombokTest() {
}
public boolean isFlag() {
return this.flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}複製代碼
能夠看到boolean類型的get方法是isFlag()而不是getFlag()。咱們還可定義生成get和set方法的訪問級別。函數
public class LombokTest {
@Getter(AccessLevel.PUBLIC)
@Setter(AccessLevel.PROTECTED)
private String name;
}複製代碼
編譯後的代碼(等效Java代碼)工具
public class LombokTest {
private String name;
public LombokTest() {
}
public String getName() {
return this.name;
}
protected void setName(String name) {
this.name = name;
}
}複製代碼
能夠看到setName的訪問級別是protected。lombok提供了下面幾種級別。
AccessLevel枚舉類的源代碼。
public enum AccessLevel {
PUBLIC, // public
MODULE, // 編譯後至關於 default
PROTECTED, // protected
PACKAGE, // default
PRIVATE, // private
NONE; // 不生成
private AccessLevel() {
}
}複製代碼
最後@Getter和@Setter註解是能夠寫在類級別的,做用於全部的成員變量,沒法細粒度的控制訪問級別。
@Getter(AccessLevel.MODULE)
@Setter(AccessLevel.PROTECTED)
public class LombokTest {
private String name;
private boolean flag;
}複製代碼
編譯後的代碼(等效Java代碼)
public class LombokTest {
private String name;
private boolean flag;
public LombokTest() {
}
String getName() {
return this.name;
}
boolean isFlag() {
return this.flag;
}
protected void setName(String name) {
this.name = name;
}
protected void setFlag(boolean flag) {
this.flag = flag;
}
}複製代碼
變量空檢查,若是@NonNull註解使用在構造函數的字段時,構造函數也會進行空變量檢查。不可用於類級別。
public class LombokTest {
@NonNull
@Setter
@Getter
private String name;
public LombokTest(@NonNull String name) {
this.name = name;
}
}複製代碼
編譯後的代碼(等效Java代碼)
public class LombokTest {
@NonNull
private String name;
public LombokTest(@NonNull String name) {
if (name == null) {
throw new NullPointerException("name is marked @NonNull but is null");
} else {
this.name = name;
}
}
public void setName(@NonNull String name) {
if (name == null) {
throw new NullPointerException("name is marked @NonNull but is null");
} else {
this.name = name;
}
}
@NonNull
public String getName() {
return this.name;
}
}複製代碼
用於生成toString()方法。只能用於類級別。static修飾的變量是不能生成在toString()方法中的,緣由是static修飾的變量在類建立的時候就生成了,只有一個;而普通的變量屬於對象,每建立一個新的對象都會有一個。能夠理解爲static修飾的變量屬於類,而普通變量數據對象,這樣可能好理解一點。
@ToString
public class LombokTest {
private String name;
private static String phone;
}複製代碼
編譯後的代碼(等效Java代碼)
public class LombokTest {
private String name;
private static String phone;
public LombokTest() {
}
public String toString() {
return "YmlProperties(name=" + this.name + ")";
}
}複製代碼
默認狀況下出了static修飾的字段都將以name-value的形式生成在toString()方法中。同時toString註解中還能夠設置一些屬性來細粒度的控制toString()方法。
下面是ToString註解的源碼和解釋:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface ToString {
boolean includeFieldNames() default true; // 生成toString()方法時默認爲 name-value的形式,設置爲false時 則 value的形式。
String[] exclude() default {}; // 不包含指定字段
String[] of() default {}; // 包含指定字段
boolean callSuper() default false; // 是否調用父類的toString()方法
boolean doNotUseGetters() default false; // 生成toString()方法是否直接訪問字段,設置爲true時直接訪問字段(如:this.name),false時經過getter()方法進行訪問(如:this.getName())。固然若是沒有生成getter()方法,不管是否設置都直接訪問字段
boolean onlyExplicitlyIncluded() default false; // 是否僅僅包含添加了@ToString.Include的字段,默認爲false。
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
public @interface Exclude { // 使用@ToString.Exclude修飾字段,須要和@ToString註解一塊兒使用,單獨使用無效。
}
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Include {// 使用@ToString.Include修飾字段,須要和@ToString註解一塊兒使用,單獨使用無效。
int rank() default 0;
String name() default "";
}
}複製代碼
注意:
@ToString(of = {"name","phone"}) // 包含name和phone字段
@ToString(exclude = {"name","phone"}) // 不包含name和phone字段複製代碼
@ToString
public class LombokTest {
@ToString.Include
private String name;
@ToString.Exclude
private String phone;
}複製代碼
生成equals()和hashCode()方法。默認使用全部的非static和非transient字段生成這兩個方法。
@EqualsAndHashCode
public class LombokTest {
private String name;
private String phone;
private boolean flag;
}複製代碼
編譯後的代碼(等效Java代碼)
public class LombokTest {
private String name;
private String phone;
private boolean flag;
public LombokTest() {
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof LombokTest)) {
return false;
} else {
LombokTest other = (LombokTest)o;
if (!other.canEqual(this)) {
return false;
} else {
label39: {
Object this$name = this.name;
Object other$name = other.name;
if (this$name == null) {
if (other$name == null) {
break label39;
}
} else if (this$name.equals(other$name)) {
break label39;
}
return false;
}
Object this$phone = this.phone;
Object other$phone = other.phone;
if (this$phone == null) {
if (other$phone != null) {
return false;
}
} else if (!this$phone.equals(other$phone)) {
return false;
}
if (this.flag != other.flag) {
return false;
} else {
return true;
}
}
}
}
protected boolean canEqual(Object other) {
return other instanceof LombokTest;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $name = this.name;
int result = result * 59 + ($name == null ? 43 : $name.hashCode());
Object $phone = this.phone;
result = result * 59 + ($phone == null ? 43 : $phone.hashCode());
result = result * 59 + (this.flag ? 79 : 97);
return result;
}
}複製代碼
和ToString註解類似也能夠經過設置一些屬性來控制決堤生成的hashCode()和equals()方法。下面是@EqualsAndHashCode註解的源碼和解釋,和@ToString同樣的屬性就沒有寫註釋了。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface EqualsAndHashCode {
String[] exclude() default {};
String[] of() default {};
boolean callSuper() default false;// 是否使用父類的equals和toString方法,注意:父類爲Object時沒法設置爲true。
boolean doNotUseGetters() default false;
EqualsAndHashCode.AnyAnnotation[] onParam() default {};
boolean onlyExplicitlyIncluded() default false;
/** @deprecated */
@Deprecated
@Retention(RetentionPolicy.SOURCE)
@Target({})
public @interface AnyAnnotation { // 過期的方法(deprecated)
}
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.SOURCE)
public @interface Exclude {
}
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Include {
String replaces() default "";
}
}複製代碼
這是lombok中使用的最多的註解,至關於@ToString
,@EqualsAndHashCode
, @RequiredArgsConstructor
,@Getter
和@Setter
五個註解的功能。雖然使用起來方法,可是失去了細粒度的控制。若是須要細粒度控制,則須要進行註解的覆蓋。
@Data
public class LombokTest {
private String name;
private String phone;
private boolean flag;
}複製代碼
編譯後的代碼(等效Java代碼)
public class LombokTest {
private String name;
private String phone;
private boolean flag;
public LombokTest() {
}
public String getName() {
return this.name;
}
public String getPhone() {
return this.phone;
}
public boolean isFlag() {
return this.flag;
}
public void setName(String name) {
this.name = name;
}
public void setPhone(String phone) {
this.phone = phone;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof LombokTest)) {
return false;
} else {
LombokTest other = (LombokTest)o;
if (!other.canEqual(this)) {
return false;
} else {
label39: {
Object this$name = this.getName();
Object other$name = other.getName();
if (this$name == null) {
if (other$name == null) {
break label39;
}
} else if (this$name.equals(other$name)) {
break label39;
}
return false;
}
Object this$phone = this.getPhone();
Object other$phone = other.getPhone();
if (this$phone == null) {
if (other$phone != null) {
return false;
}
} else if (!this$phone.equals(other$phone)) {
return false;
}
if (this.isFlag() != other.isFlag()) {
return false;
} else {
return true;
}
}
}
}
protected boolean canEqual(Object other) {
return other instanceof LombokTest;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $name = this.getName();
int result = result * 59 + ($name == null ? 43 : $name.hashCode());
Object $phone = this.getPhone();
result = result * 59 + ($phone == null ? 43 : $phone.hashCode());
result = result * 59 + (this.isFlag() ? 79 : 97);
return result;
}
public String toString() {
return "LombokTest(name=" + this.getName() + ", phone=" + this.getPhone() + ", flag=" + this.isFlag() + ")";
}
}複製代碼
下面看一下@Data註解的源碼。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface Data {
String staticConstructor() default "";
}複製代碼
能夠看到提供了一個,staticConstructor(),這個方法的做用是私有化構造器,並生成一個靜態的獲取實例的方法,這樣就可經過類名來獲取實例(如:LombokTest.getLombokTest())
@Data(staticConstructor = "getLombokTest")複製代碼
private LombokTest() {
}
public static LombokTest getLombokTest() {
return new LombokTest();
}
// ...省略其餘代碼複製代碼
自動釋放資源,主要用於IO流的操做,不須要手動編寫釋放資源的try/finally
代碼塊。
public class LombokTest {
public static void main(String[] args) throws Exception {
@Cleanup InputStream is = new FileInputStream(args[0]);
@Cleanup OutputStream os = new FileOutputStream(args[0]);
}
}複製代碼
編譯後的代碼(等效Java代碼)
public class LombokTest {
public static void main(String[] args) throws Exception {
FileInputStream is = new FileInputStream(args[0]);
try {
OutputStream os = new FileOutputStream(args[0]);
if (Collections.singletonList(os).get(0) != null) {
os.close();
}
} finally {
if (Collections.singletonList(is).get(0) != null) {
is.close();
}
}
}
}複製代碼
仍是挺方便的。再來看看@Cleanup註解的源代碼
@Target({ElementType.LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface Cleanup {
String value() default "close";
}複製代碼
能夠看到默認調用的是close方法,也就是說咱們能夠設置finally方法體具體調用的流處理方法。如:
public static void main(String[] args) throws Exception {
@Cleanup(value = "available") InputStream is = new FileInputStream(args[0]);
@Cleanup OutputStream os = new FileOutputStream(args[0]);
}複製代碼
編譯後的代碼(等效Java代碼)
具體能夠指定哪些字段,須要流對象支持哪些方法了。如InputStream:
同步代碼塊,只能使用在類方法(static)或者對象方法(普通方法)上,synchronized關鍵字鎖住的是this,@Synchronized註解默認使用的鎖爲$lock,靜態的鎖爲$LOCK,也能夠本身指定鎖對象,如示例中的:world
public class LombokTest {
@Synchronized
public void hello() {
}
@Synchronized
public static void helloWorld() {
}
private final Object world = new Object();
@Synchronized("world")
public void world() {
}
}複製代碼
編譯後的代碼(等效Java代碼)
public class LombokTest {
private final Object $lock = new Object[0];
private static final Object $LOCK = new Object[0];
private final Object world = new Object();
public LombokTest() {
}
public void hello() {
Object var1 = this.$lock;
synchronized(this.$lock) {
;
}
}
public static void helloWorld() {
Object var0 = $LOCK;
synchronized($LOCK) {
;
}
}
public void world() {
Object var1 = this.world;
synchronized(this.world) {
;
}
}
}複製代碼
我的以爲沒有啥意義,惟一的做用可能就是不用手動捕獲異常或者向上拋出,而是經過lombok幫你捕獲。。。能夠指定捕獲的異常類型,默認捕獲的是Throwable。
public class LombokTest {
@SneakyThrows()
public void testSneakyThrows() {
throw new IllegalAccessException();
}
@SneakyThrows(IllegalAccessException.class)
public void testSneakyThrows2() {
throw new IllegalAccessException();
}
}複製代碼
編譯後的代碼(等效Java代碼)
public class LombokTest {
public LombokTest() {
}
public void testSneakyThrows() {
try {
throw new IllegalAccessException();
} catch (Throwable var2) {
throw var2;
}
}
public void testSneakyThrows2() {
try {
throw new IllegalAccessException();
} catch (IllegalAccessException var2) {
throw var2;
}
}
}複製代碼
感受有點呆。。。官方建議在沒有深思熟慮以前不要使用這個註解。。。下面是官網上的一句話:
@SneakyThrows
annotation. If you pass no exceptions, you may throw any exception sneakily. @NoArgsConstructor 生成一個無參構造器。
@NoArgsConstructor註解源代碼,另外兩個註解的源碼和這個很相似,就不貼出來了。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public @interface NoArgsConstructor {
String staticName() default ""; // 若是指定了相應字段,則私有化構造並生成一個靜態的獲取實例方法。
NoArgsConstructor.AnyAnnotation[] onConstructor() default {};
AccessLevel access() default AccessLevel.PUBLIC;
boolean force() default false;
/** @deprecated */
@Deprecated
@Retention(RetentionPolicy.SOURCE)
@Target({})
public @interface AnyAnnotation { // 過期的(deprecated)
}
}複製代碼
@ RequiredArgsConstructor 生成包含必須處理的字段的構造器,如:final修飾(必須初始化)、@NonNull註解修飾的。
@RequiredArgsConstructor
public class LombokTest {
private String name;
private String phone;
private transient boolean flag;
private final String finalFiled;
private static int num;
}複製代碼
編譯後的代碼(等效Java代碼)
public class LombokTest {
private String name;
private String phone;
private transient boolean flag;
private final String finalFiled;
private static int num;
public LombokTest(String finalFiled) {
this.finalFiled = finalFiled;
}
}複製代碼
@ AllArgsConstructor 生成一個全參構造器,除static修飾的字段。@NonNull能夠組合使用。
@AllArgsConstructor
public class LombokTest {
private String name;
@NonNull
private String phone;
private transient boolean flag;
private final String finalFiled;
private static int num;
}複製代碼
編譯後的代碼(等效Java代碼)
public class LombokTest {
private String name;
@NonNull
private String phone;
private transient boolean flag;
private final String finalFiled;
private static int num;
public LombokTest(String name, @NonNull String phone, boolean flag, String finalFiled) {
if (phone == null) {
throw new NullPointerException("phone is marked @NonNull but is null");
} else {
this.name = name;
this.phone = phone;
this.flag = flag;
this.finalFiled = finalFiled;
}
}
}複製代碼
學到這裏經常使用的Lombok註解基本上都有了,若是想要根據深刻的學習,建議去官網看。官網地址文章開始已經列出來了,加油!!!