Lombok 使用指南
0x01:Lombok簡介
Lombok 是一款 Java開發(fā)插件,使得 Java 開發(fā)者可以通過其定義的一些注解來消除業(yè)務(wù)工程中冗長和繁瑣的代碼,尤其對于簡單的 Java 模型對象(POJO)。在開發(fā)環(huán)境中使用 Lombok插件后,Java 開發(fā)人員可以節(jié)省出重復(fù)構(gòu)建,諸如 hashCode 和 equals 這樣的方法以及各種業(yè)務(wù)對象模型的 accessor 和 toString 等方法的大量時(shí)間。對于這些方法,Lombok 能夠在編譯源代碼期間自動(dòng)幫我們生成這些方法,但并不會像反射那樣降低程序的性能。
0x02:Lombok安裝
構(gòu)建工具
Gradle
在 build.gradle 文件中添加 Lombok 依賴:
dependencies?{
????compileOnly?'org.projectlombok:lombok:1.18.10'
????annotationProcessor?'org.projectlombok:lombok:1.18.10'
}
Maven
在 Maven 項(xiàng)目的 pom.xml 文件中添加 Lombok 依賴:
<dependency>
????<groupId>org.projectlombok</groupId>
????<artifactId>lombok</artifactId>
????<version>1.18.10</version>
????<scope>provided</scope>
</dependency>Ant
假設(shè)在 lib 目錄中已經(jīng)存在 lombok.jar,然后設(shè)置 javac 任務(wù):
<javac?srcdir="src"?destdir="build"?source="1.8">
????<classpath?location="lib/lombok.jar"?/>
</javac>
IDE
由于 Lombok 僅在編譯階段生成代碼,所以使用 Lombok 注解的源代碼,在 IDE 中會被高亮顯示錯(cuò)誤,針對這個(gè)問題可以通過安裝 IDE 對應(yīng)的插件來解決。這里不詳細(xì)展開,具體的安裝方式可以參考:
https://www.baeldung.com/lombok-ide
0x03:Lombok 詳解
注意:以下示例所使用的 Lombok 版本是 1.18.10
3.1 @Getter? and @Setter?
你可以使用 @Getter 或 @Setter 注釋任何類或字段,Lombok 會自動(dòng)生成默認(rèn)的 getter/setter 方法。
@Getter? 注解?
@Target({ElementType.FIELD,?ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public?@interface?Getter?{
??//?若getter方法非public的話,可以設(shè)置可訪問級別
????lombok.AccessLevel?value()?default?lombok.AccessLevel.PUBLIC;
????AnyAnnotation[]?onMethod()?default?{};
??//?是否啟用延遲初始化
????boolean?lazy()?default?false;
}@Setter?
@Target({ElementType.FIELD,?ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public?@interface?Setter?{
??//?若setter方法非public的話,可以設(shè)置可訪問級別
????lombok.AccessLevel?value()?default?lombok.AccessLevel.PUBLIC;
????AnyAnnotation[]?onMethod()?default?{};
????AnyAnnotation[]?onParam()?default?{};
}
使用示例
@Getter
@Setter
public?class?GetterAndSetterDemo?{
????String?firstName;
????String?lastName;
????LocalDate?dateOfBirth;
}
以上代碼經(jīng)過 Lombok 編譯后,會生成如下代碼:
public?class?GetterAndSetterDemo?{
????String?firstName;
????String?lastName;
????LocalDate?dateOfBirth;
????public?GetterAndSetterDemo()?{
????}
????//?省略其它setter和getter方法
????public?String?getFirstName()?{
????????return?this.firstName;
????}
????public?void?setFirstName(String?firstName)?{
????????this.firstName?=?firstName;
????}
}
Lazy Getter
@Getter ?注解支持一個(gè) lazy 屬性,該屬性默認(rèn)為 false。當(dāng)設(shè)置為 true 時(shí),會啟用延遲初始化,即當(dāng)首次調(diào)用 getter 方法時(shí)才進(jìn)行初始化。?
示例
public?class?LazyGetterDemo?{
????public?static?void?main(String[]?args)?{
????????LazyGetterDemo?m?=?new?LazyGetterDemo();
????????System.out.println("Main?instance?is?created");
????????m.getLazy();
????}
????@Getter
????private?final?String?notLazy?=?createValue("not?lazy");
????@Getter(lazy?=?true)
????private?final?String?lazy?=?createValue("lazy");
????private?String?createValue(String?name)?{
????????System.out.println("createValue("?+?name?+?")");
????????return?null;
????}
}
以上代碼經(jīng)過 Lombok 編譯后,會生成如下代碼:
public?class?LazyGetterDemo?{
????private?final?String?notLazy?=?this.createValue("not?lazy");
????private?final?AtomicReference<Object>?lazy?=?new?AtomicReference();
????//?已省略部分代碼
????public?String?getNotLazy()?{
????????return?this.notLazy;
????}
????public?String?getLazy()?{
????????Object?value?=?this.lazy.get();
????????if?(value?==?null)?{
????????????synchronized(this.lazy)?{
????????????????value?=?this.lazy.get();
????????????????if?(value?==?null)?{
????????????????????String?actualValue?=?this.createValue("lazy");
????????????????????value?=?actualValue?==?null???this.lazy?:?actualValue;
????????????????????this.lazy.set(value);
????????????????}
????????????}
????????}
????????return?(String)((String)(value?==?this.lazy???null?:?value));
????}
}
通過以上代碼可知,調(diào)用 getLazy 方法時(shí),若發(fā)現(xiàn) value 為 null,則會在同步代碼塊中執(zhí)行初始化操作。
3.2 Constructor Annotations
@NoArgsConstructor?
使用 @NoArgsConstructor ?注解可以為指定類,生成默認(rèn)的構(gòu)造函數(shù),@NoArgsConstructor ?注解的定義如下:?
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public?@interface?NoArgsConstructor?{
??//?若設(shè)置該屬性,將會生成一個(gè)私有的構(gòu)造函數(shù)且生成一個(gè)staticName指定的靜態(tài)方法
????String?staticName()?default?"";
????AnyAnnotation[]?onConstructor()?default?{};
??//?設(shè)置生成構(gòu)造函數(shù)的訪問級別,默認(rèn)是public
????AccessLevel?access()?default?lombok.AccessLevel.PUBLIC;
??//?若設(shè)置為true,則初始化所有final的字段為0/null/false
????boolean?force()?default?false;
}
示例
@NoArgsConstructor(staticName?=?"getInstance")
public?class?NoArgsConstructorDemo?{
????private?long?id;
????private?String?name;
????private?int?age;
}
以上代碼經(jīng)過 Lombok 編譯后,會生成如下代碼:
public?class?NoArgsConstructorDemo?{
????private?long?id;
????private?String?name;
????private?int?age;
????private?NoArgsConstructorDemo()?{
????}
????public?static?NoArgsConstructorDemo?getInstance()?{
????????return?new?NoArgsConstructorDemo();
????}
}
@AllArgsConstructor?
使用 @AllArgsConstructor ?注解可以為指定類,生成包含所有成員的構(gòu)造函數(shù),@AllArgsConstructor ?注解的定義如下:?
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public?@interface?AllArgsConstructor?{
??//?若設(shè)置該屬性,將會生成一個(gè)私有的構(gòu)造函數(shù)且生成一個(gè)staticName指定的靜態(tài)方法
????String?staticName()?default?"";
????AnyAnnotation[]?onConstructor()?default?{};
??//?設(shè)置生成構(gòu)造函數(shù)的訪問級別,默認(rèn)是public
????AccessLevel?access()?default?lombok.AccessLevel.PUBLIC;
}
示例
@AllArgsConstructor
public?class?AllArgsConstructorDemo?{
????private?long?id;
????private?String?name;
????private?int?age;
}
以上代碼經(jīng)過 Lombok 編譯后,會生成如下代碼:
public?class?AllArgsConstructorDemo?{
????private?long?id;
????private?String?name;
????private?int?age;
????public?AllArgsConstructorDemo(long?id,?String?name,?int?age)?{
????????this.id?=?id;
????????this.name?=?name;
????????this.age?=?age;
????}
}
@RequiredArgsConstructor
使用 @RequiredArgsConstructor 注解可以為指定類必需初始化的成員變量,如 final 成員變量,生成對應(yīng)的構(gòu)造函數(shù),@RequiredArgsConstructor 注解的定義如下:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public?@interface?RequiredArgsConstructor?{
??//?若設(shè)置該屬性,將會生成一個(gè)私有的構(gòu)造函數(shù)且生成一個(gè)staticName指定的靜態(tài)方法
????String?staticName()?default?"";
????AnyAnnotation[]?onConstructor()?default?{};
??//?設(shè)置生成構(gòu)造函數(shù)的訪問級別,默認(rèn)是public
????AccessLevel?access()?default?lombok.AccessLevel.PUBLIC;
}
示例
@RequiredArgsConstructor
public?class?RequiredArgsConstructorDemo?{
????private?final?long?id;
????private?String?name;
????private?int?age;
}以上代碼經(jīng)過 Lombok 編譯后,會生成如下代碼:
public?class?RequiredArgsConstructorDemo?{
????private?final?long?id;
????private?String?name;
????private?int?age;
????public?RequiredArgsConstructorDemo(long?id)?{
????????this.id?=?id;
????}
}
3.3 @EqualsAndHashCode?
使用 @EqualsAndHashCode ?注解可以為指定類生成 equals 和 hashCode 方法, @EqualsAndHashCode ?注解的定義如下:?
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public?@interface?EqualsAndHashCode?{
??//?指定在生成的equals和hashCode方法中需要排除的字段列表
????String[]?exclude()?default?{};
??//?顯式列出用于identity的字段,一般情況下non-static,non-transient字段會被用于identity
????String[]?of()?default?{};
??//?標(biāo)識在執(zhí)行字段計(jì)算前,是否調(diào)用父類的equals和hashCode方法
????boolean?callSuper()?default?false;
????boolean?doNotUseGetters()?default?false;
????AnyAnnotation[]?onParam()?default?{};
????@Deprecated
????@Retention(RetentionPolicy.SOURCE)
????@Target({})
????@interface?AnyAnnotation?{}
????@Target(ElementType.FIELD)
????@Retention(RetentionPolicy.SOURCE)
????public?@interface?Exclude?{}
????@Target({ElementType.FIELD,?ElementType.METHOD})
????@Retention(RetentionPolicy.SOURCE)
????public?@interface?Include?{
????????String?replaces()?default?"";
????}
}
示例
@EqualsAndHashCode
public?class?EqualsAndHashCodeDemo?{
????String?firstName;
????String?lastName;
????LocalDate?dateOfBirth;
}
以上代碼經(jīng)過 Lombok 編譯后,會生成如下代碼:
public?class?EqualsAndHashCodeDemo?{
????String?firstName;
????String?lastName;
????LocalDate?dateOfBirth;
????public?EqualsAndHashCodeDemo()?{
????}
????public?boolean?equals(Object?o)?{
????????if?(o?==?this)?{
????????????return?true;
????????}?else?if?(!(o?instanceof?EqualsAndHashCodeDemo))?{
????????????return?false;
????????}?else?{
????????????EqualsAndHashCodeDemo?other?=?(EqualsAndHashCodeDemo)o;
????????????if?(!other.canEqual(this))?{
????????????????return?false;
????????????}?else?{
??????????????//?已省略大量代碼
????????}
????}
????public?int?hashCode()?{
????????int?PRIME?=?true;
????????int?result?=?1;
????????Object?$firstName?=?this.firstName;
????????int?result?=?result?*?59?+?($firstName?==?null???43?:?$firstName.hashCode());
????????Object?$lastName?=?this.lastName;
????????result?=?result?*?59?+?($lastName?==?null???43?:?$lastName.hashCode());
????????Object?$dateOfBirth?=?this.dateOfBirth;
????????result?=?result?*?59?+?($dateOfBirth?==?null???43?:?$dateOfBirth.hashCode());
????????return?result;
????}
}
3.4 @ToString?
使用 @ToString ?注解可以為指定類生成 toString 方法, @ToString ?注解的定義如下:?
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public?@interface?ToString?{
??//?打印輸出時(shí)是否包含字段的名稱
????boolean?includeFieldNames()?default?true;
??//?列出打印輸出時(shí),需要排除的字段列表
????String[]?exclude()?default?{};
??//?顯式的列出需要打印輸出的字段列表
????String[]?of()?default?{};
??//?打印輸出的結(jié)果中是否包含父類的toString方法的返回結(jié)果
????boolean?callSuper()?default?false;
????boolean?doNotUseGetters()?default?false;
????boolean?onlyExplicitlyIncluded()?default?false;
????@Target(ElementType.FIELD)
????@Retention(RetentionPolicy.SOURCE)
????public?@interface?Exclude?{}
????@Target({ElementType.FIELD,?ElementType.METHOD})
????@Retention(RetentionPolicy.SOURCE)
????public?@interface?Include?{
????????int?rank()?default?0;
????????String?name()?default?"";
????}
}
示例
@ToString(exclude?=?{"dateOfBirth"})
public?class?ToStringDemo?{
????String?firstName;
????String?lastName;
????LocalDate?dateOfBirth;
}
以上代碼經(jīng)過 Lombok 編譯后,會生成如下代碼:
public?class?ToStringDemo?{
????String?firstName;
????String?lastName;
????LocalDate?dateOfBirth;
????public?ToStringDemo()?{
????}
????public?String?toString()?{
????????return?"ToStringDemo(firstName="?+?this.firstName?+?",?lastName="?+
??????????this.lastName?+?")";
????}
}
3.5 @Data?
@Data ?注解與同時(shí)使用以下的注解的效果是一樣的:?
@ToString
@Getter
@Setter
@RequiredArgsConstructor
@EqualsAndHashCode
@Data ?注解的定義如下:?
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public?@interface?Data?{
????String?staticConstructor()?default?"";
}
示例
@Data
public?class?DataDemo?{
????private?Long?id;
????private?String?summary;
????private?String?description;
}
以上代碼經(jīng)過 Lombok 編譯后,會生成如下代碼:
public?class?DataDemo?{
????private?Long?id;
????private?String?summary;
????private?String?description;
????public?DataDemo()?{
????}
????//?省略summary和description成員屬性的setter和getter方法
????public?Long?getId()?{
????????return?this.id;
????}
????public?void?setId(Long?id)?{
????????this.id?=?id;
????}
????public?boolean?equals(Object?o)?{
????????if?(o?==?this)?{
????????????return?true;
????????}?else?if?(!(o?instanceof?DataDemo))?{
????????????return?false;
????????}?else?{
????????????DataDemo?other?=?(DataDemo)o;
????????????if?(!other.canEqual(this))?{
????????????????return?false;
????????????}?else?{
???????????????//?已省略大量代碼
????????????}
????????}
????}
????protected?boolean?canEqual(Object?other)?{
????????return?other?instanceof?DataDemo;
????}
????public?int?hashCode()?{
????????int?PRIME?=?true;
????????int?result?=?1;
????????Object?$id?=?this.getId();
????????int?result?=?result?*?59?+?($id?==?null???43?:?$id.hashCode());
????????Object?$summary?=?this.getSummary();
????????result?=?result?*?59?+?($summary?==?null???43?:?$summary.hashCode());
????????Object?$description?=?this.getDescription();
????????result?=?result?*?59?+?($description?==?null???43?:?$description.hashCode());
????????return?result;
????}
????public?String?toString()?{
????????return?"DataDemo(id="?+?this.getId()?+?",?summary="?+?this.getSummary()?+?",?description="?+?this.getDescription()?+?")";
????}
}
3.6 @Log?
若你將 @Log ?的變體放在類上(適用于你所使用的日志記錄系統(tǒng)的任何一種);之后,你將擁有一個(gè)靜態(tài)的 final log 字段,然后你就可以使用該字段來輸出日志。?
@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);
@CommonsLog
private?static?final?org.apache.commons.logging.Log?log?=?org.apache.commons.logging.LogFactory.getLog(LogExample.class);
3.7 @Synchronized?
@Synchronized ?是同步方法修飾符的更安全的變體。與 synchronized 一樣,該注解只能應(yīng)用在靜態(tài)和實(shí)例方法上。它的操作類似于 synchronized 關(guān)鍵字,但是它鎖定在不同的對象上。synchronized 關(guān)鍵字應(yīng)用在實(shí)例方法時(shí),鎖定的是 this 對象,而應(yīng)用在靜態(tài)方法上鎖定的是類對象。對于 @Synchronized ?注解聲明的方法來說,它鎖定的是 或lock。@Synchronized ?注解的定義如下:?
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public?@interface?Synchronized?{
??//?指定鎖定的字段名稱
????String?value()?default?"";
}
示例
public?class?SynchronizedDemo?{
????private?final?Object?readLock?=?new?Object();
????@Synchronized
????public?static?void?hello()?{
????????System.out.println("world");
????}
????@Synchronized
????public?int?answerToLife()?{
????????return?42;
????}
????@Synchronized("readLock")
????public?void?foo()?{
????????System.out.println("bar");
????}
}
以上代碼經(jīng)過 Lombok 編譯后,會生成如下代碼:
public?class?SynchronizedDemo?{
????private?static?final?Object?$LOCK?=?new?Object[0];
????private?final?Object?$lock?=?new?Object[0];
????private?final?Object?readLock?=?new?Object();
????public?SynchronizedDemo()?{
????}
????public?static?void?hello()?{
????????synchronized($LOCK)?{
????????????System.out.println("world");
????????}
????}
????public?int?answerToLife()?{
????????synchronized(this.$lock)?{
????????????return?42;
????????}
????}
????public?void?foo()?{
????????synchronized(this.readLock)?{
????????????System.out.println("bar");
????????}
????}
}
3.8 @Builder?
使用 @Builder ?注解可以為指定類實(shí)現(xiàn)建造者模式,該注解可以放在類、構(gòu)造函數(shù)或方法上。@Builder ?注解的定義如下:?
@Target({TYPE,?METHOD,?CONSTRUCTOR})
@Retention(SOURCE)
public?@interface?Builder?{
????@Target(FIELD)
????@Retention(SOURCE)
????public?@interface?Default?{}
??//?創(chuàng)建新的builder實(shí)例的方法名稱
????String?builderMethodName()?default?"builder";
????//?創(chuàng)建Builder注解類對應(yīng)實(shí)例的方法名稱
????String?buildMethodName()?default?"build";
????//?builder類的名稱
????String?builderClassName()?default?"";
????boolean?toBuilder()?default?false;
????AccessLevel?access()?default?lombok.AccessLevel.PUBLIC;
????@Target({FIELD,?PARAMETER})
????@Retention(SOURCE)
????public?@interface?ObtainVia?{
????????String?field()?default?"";
????????String?method()?default?"";
????????boolean?isStatic()?default?false;
????}
}
示例
@Builder
public?class?BuilderDemo?{
????private?final?String?firstname;
????private?final?String?lastname;
????private?final?String?email;
}
以上代碼經(jīng)過 Lombok 編譯后,會生成如下代碼:
public?class?BuilderDemo?{
????private?final?String?firstname;
????private?final?String?lastname;
????private?final?String?email;
????BuilderDemo(String?firstname,?String?lastname,?String?email)?{
????????this.firstname?=?firstname;
????????this.lastname?=?lastname;
????????this.email?=?email;
????}
????public?static?BuilderDemo.BuilderDemoBuilder?builder()?{
????????return?new?BuilderDemo.BuilderDemoBuilder();
????}
????public?static?class?BuilderDemoBuilder?{
????????private?String?firstname;
????????private?String?lastname;
????????private?String?email;
????????BuilderDemoBuilder()?{
????????}
????????public?BuilderDemo.BuilderDemoBuilder?firstname(String?firstname)?{
????????????this.firstname?=?firstname;
????????????return?this;
????????}
????????public?BuilderDemo.BuilderDemoBuilder?lastname(String?lastname)?{
????????????this.lastname?=?lastname;
????????????return?this;
????????}
????????public?BuilderDemo.BuilderDemoBuilder?email(String?email)?{
????????????this.email?=?email;
????????????return?this;
????????}
????????public?BuilderDemo?build()?{
????????????return?new?BuilderDemo(this.firstname,?this.lastname,?this.email);
????????}
????????public?String?toString()?{
????????????return?"BuilderDemo.BuilderDemoBuilder(firstname="?+?this.firstname?+?",?lastname="?+?this.lastname?+?",?email="?+?this.email?+?")";
????????}
????}
}
3.9 @SneakyThrows?
@SneakyThrows ?注解用于自動(dòng)拋出已檢查的異常,而無需在方法中使用 throw 語句顯式拋出。@SneakyThrows ?注解的定義如下:?
@Target({ElementType.METHOD,?ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.SOURCE)
public?@interface?SneakyThrows?{
????//?設(shè)置你希望向上拋的異常類
????Class<??extends?Throwable>[]?value()?default?java.lang.Throwable.class;
}
示例
public?class?SneakyThrowsDemo?{
????@SneakyThrows
????@Override
????protected?Object?clone()?{
????????return?super.clone();
????}
}
以上代碼經(jīng)過 Lombok 編譯后,會生成如下代碼:
public?class?SneakyThrowsDemo?{
????public?SneakyThrowsDemo()?{
????}
????protected?Object?clone()?{
????????try?{
????????????return?super.clone();
????????}?catch?(Throwable?var2)?{
????????????throw?var2;
????????}
????}
}
3.10 @NonNull?
你可以在方法或構(gòu)造函數(shù)的參數(shù)上使用 @NonNull ?注解,它將會為你自動(dòng)生成非空校驗(yàn)語句。@NonNull ?注解的定義如下:?
@Target({ElementType.FIELD,?ElementType.METHOD,?ElementType.PARAMETER,?ElementType.LOCAL_VARIABLE,?ElementType.TYPE_USE})
@Retention(RetentionPolicy.CLASS)
@Documented
public?@interface?NonNull?{
}
示例
public?class?NonNullDemo?{
????@Getter
????@Setter
????@NonNull
????private?String?name;
}
以上代碼經(jīng)過 Lombok 編譯后,會生成如下代碼:
public?class?NonNullDemo?{
????@NonNull
????private?String?name;
????public?NonNullDemo()?{
????}
????@NonNull
????public?String?getName()?{
????????return?this.name;
????}
????public?void?setName(@NonNull?String?name)?{
????????if?(name?==?null)?{
????????????throw?new?NullPointerException("name?is?marked?non-null?but?is?null");
????????}?else?{
????????????this.name?=?name;
????????}
????}
}
3.11 @Clean?
@Clean ?注解用于自動(dòng)管理資源,用在局部變量之前,在當(dāng)前變量范圍內(nèi)即將執(zhí)行完畢退出之前會自動(dòng)清理資源,自動(dòng)生成 try-finally 這樣的代碼來關(guān)閉流。?
@Target(ElementType.LOCAL_VARIABLE)
@Retention(RetentionPolicy.SOURCE)
public?@interface?Cleanup?{
??//?設(shè)置用于執(zhí)行資源清理/回收的方法名稱,對應(yīng)方法不能包含任何參數(shù),默認(rèn)名稱為close。
????String?value()?default?"close";
}
示例
public?class?CleanupDemo?{
????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);
????????}
????}
}
以上代碼經(jīng)過 Lombok 編譯后,會生成如下代碼:
public?class?CleanupDemo?{
????public?CleanupDemo()?{
????}
????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();
????????????}
????????}
????}
}
3.11 @With?
在類的字段上應(yīng)用 @With ?注解之后,將會自動(dòng)生成一個(gè) withFieldName(newValue) 的方法,該方法會基于 newValue 調(diào)用相應(yīng)構(gòu)造函數(shù),創(chuàng)建一個(gè)當(dāng)前類對應(yīng)的實(shí)例。@With ?注解的定義如下:?
@Target({ElementType.FIELD,?ElementType.TYPE})
@Retention(RetentionPolicy.SOURCE)
public?@interface?With?{
????AccessLevel?value()?default?AccessLevel.PUBLIC;
????With.AnyAnnotation[]?onMethod()?default?{};
????With.AnyAnnotation[]?onParam()?default?{};
????@Deprecated
????@Retention(RetentionPolicy.SOURCE)
????@Target({})
????public?@interface?AnyAnnotation?{
????}
}
示例
public?class?WithDemo?{
????@With(AccessLevel.PROTECTED)
????@NonNull
????private?final?String?name;
????@With
????private?final?int?age;
????public?WithDemo(String?name,?int?age)?{
????????if?(name?==?null)?throw?new?NullPointerException();
????????this.name?=?name;
????????this.age?=?age;
????}
}
以上代碼經(jīng)過 Lombok 編譯后,會生成如下代碼:
public?class?WithDemo?{
????@NonNull
????private?final?String?name;
????private?final?int?age;
????public?WithDemo(String?name,?int?age)?{
????????if?(name?==?null)?{
????????????throw?new?NullPointerException();
????????}?else?{
????????????this.name?=?name;
????????????this.age?=?age;
????????}
????}
????protected?WithDemo?withName(@NonNull?String?name)?{
????????if?(name?==?null)?{
????????????throw?new?NullPointerException("name?is?marked?non-null?but?is?null");
????????}?else?{
????????????return?this.name?==?name???this?:?new?WithDemo(name,?this.age);
????????}
????}
????public?WithDemo?withAge(int?age)?{
????????return?this.age?==?age???this?:?new?WithDemo(this.name,?age);
????}
}
3.12 其它特性
val
val 用在局部變量前面,相當(dāng)于將變量聲明為 final,此外 Lombok 在編譯時(shí)還會自動(dòng)進(jìn)行類型推斷。val 的使用示例:
public?class?ValExample?{
??public?String?example()?{
????val?example?=?new?ArrayList<String>();
????example.add("Hello,?World!");
????val?foo?=?example.get(0);
????return?foo.toLowerCase();
??}
??public?void?example2()?{
????val?map?=?new?HashMap<Integer,?String>();
????map.put(0,?"zero");
????map.put(5,?"five");
????for?(val?entry?:?map.entrySet())?{
??????System.out.printf("%d:?%s\n",?entry.getKey(),?entry.getValue());
????}
??}
}
以上代碼等價(jià)于:
public?class?ValExample?{
??public?String?example()?{
????final?ArrayList<String>?example?=?new?ArrayList<String>();
????example.add("Hello,?World!");
????final?String?foo?=?example.get(0);
????return?foo.toLowerCase();
??}
??public?void?example2()?{
????final?HashMap<Integer,?String>?map?=?new?HashMap<Integer,?String>();
????map.put(0,?"zero");
????map.put(5,?"five");
????for?(final?Map.Entry<Integer,?String>?entry?:?map.entrySet())?{
??????System.out.printf("%d:?%s\n",?entry.getKey(),?entry.getValue());
????}
??}
}
至此功能強(qiáng)大的 Lombok 工具就介紹完畢了。
source:https://www.yuque.com/fengzheng-fly67/zln9pu/hgu2wb

喜歡,在看
