java: 程序包lombok不存在_Java开发神器:Lombok 学习指南
點擊上方“Java知音”,選擇“置頂公眾號”
技術文章第一時間送達!
作者:semlinker
www.segmentfault.com/a/1190000020864572
一、Lombok 簡介
Lombok 是一款 Java 開發插件,使得 Java 開發者可以通過其定義的一些注解來消除業務工程中冗長和繁瑣的代碼,尤其對于簡單的 Java 模型對象(POJO)。
在開發環境中使用 Lombok 插件后,Java 開發人員可以節省出重復構建,諸如 hashCode 和 equals 這樣的方法以及各種業務對象模型的 accessor 和 toString 等方法的大量時間。
對于這些方法,Lombok 能夠在編譯源代碼期間自動幫我們生成這些方法,但并不會像反射那樣降低程序的性能。
二、Lombok 安裝
2.1 構建工具
Gradle
在 build.gradle 文件中添加 lombok 依賴:
dependencies?{????compileOnly?'org.projectlombok:lombok:1.18.10'
????annotationProcessor?'org.projectlombok:lombok:1.18.10'
}
Maven
在 Maven 項目的 pom.xml 文件中添加 lombok 依賴:
<dependency>????????<groupId>org.projectlombokgroupId>
????????<artifactId>lombokartifactId>
????????<version>1.18.10version>
????????<scope>providedscope>
dependency>
Ant
假設在 lib 目錄中已經存在 lombok.jar,然后設置 javac 任務:
<javac?srcdir="src"?destdir="build"?source="1.8">????<classpath?location="lib/lombok.jar"?/>
javac>
2.2 IDE
由于 Lombok 僅在編譯階段生成代碼,所以使用 Lombok 注解的源代碼,在 IDE 中會被高亮顯示錯誤,針對這個問題可以通過安裝 IDE 對應的插件來解決。
這里不詳細展開,具體的安裝方式可以參考:
https://www.baeldung.com/lombok-ide
三、Lombok 詳解
注意:以下示例所使用的 Lombok 版本是 1.18.10
3.1 @Getter and @Setter 注解
你可以使用 @Getter 或 @Setter 注釋任何類或字段,Lombok 會自動生成默認的 getter/setter 方法。
@Getter 注解
@Target({ElementType.FIELD,?ElementType.TYPE})@Retention(RetentionPolicy.SOURCE)
public?@interface?Getter?{
??//?若getter方法非public的話,可以設置可訪問級別
????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的話,可以設置可訪問級別
????lombok.AccessLevel?value()?default?lombok.AccessLevel.PUBLIC;
????AnyAnnotation[]?onMethod()?default?{};
????AnyAnnotation[]?onParam()?default?{};
}
使用示例
package?com.semlinker.lombok;@Getter
@Setter
public?class?GetterAndSetterDemo?{
????String?firstName;
????String?lastName;
????LocalDate?dateOfBirth;
}
以上代碼經過 Lombok 編譯后,會生成如下代碼:
package?com.semlinker.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 注解支持一個 lazy 屬性,該屬性默認為 false。當設置為 true 時,會啟用延遲初始化,即當首次調用 getter 方法時才進行初始化。
示例
package?com.semlinker.lombok;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;
????}
}
以上代碼經過 Lombok 編譯后,會生成如下代碼:
package?com.semlinker.lombok;public?class?LazyGetterDemo?{
????private?final?String?notLazy?=?this.createValue("not?lazy");
????private?final?AtomicReference?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));
????}
}
通過以上代碼可知,調用 getLazy 方法時,若發現 value 為 null,則會在同步代碼塊中執行初始化操作。
3.2 Constructor Annotations
@NoArgsConstructor 注解
使用 @NoArgsConstructor 注解可以為指定類,生成默認的構造函數,@NoArgsConstructor 注解的定義如下:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.SOURCE)
public?@interface?NoArgsConstructor?{
??//?若設置該屬性,將會生成一個私有的構造函數且生成一個staticName指定的靜態方法
????String?staticName()?default?"";????
????AnyAnnotation[]?onConstructor()?default?{};
??//?設置生成構造函數的訪問級別,默認是public
????AccessLevel?access()?default?lombok.AccessLevel.PUBLIC;
??//?若設置為true,則初始化所有final的字段為0/null/false
????boolean?force()?default?false;
}
示例
package?com.semlinker.lombok;@NoArgsConstructor(staticName?=?"getInstance")
public?class?NoArgsConstructorDemo?{
????private?long?id;
????private?String?name;
????private?int?age;
}
以上代碼經過 Lombok 編譯后,會生成如下代碼:
package?com.semlinker.lombok;public?class?NoArgsConstructorDemo?{
????private?long?id;
????private?String?name;
????private?int?age;
????private?NoArgsConstructorDemo()?{
????}
????public?static?NoArgsConstructorDemo?getInstance()?{
????????return?new?NoArgsConstructorDemo();
????}
}
@AllArgsConstructor 注解
使用 @AllArgsConstructor 注解可以為指定類,生成包含所有成員的構造函數,@AllArgsConstructor 注解的定義如下:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.SOURCE)
public?@interface?AllArgsConstructor?{
??//?若設置該屬性,將會生成一個私有的構造函數且生成一個staticName指定的靜態方法
????String?staticName()?default?"";
????AnyAnnotation[]?onConstructor()?default?{};
??//?設置生成構造函數的訪問級別,默認是public
????AccessLevel?access()?default?lombok.AccessLevel.PUBLIC;
}
示例
package?com.semlinker.lombok;@AllArgsConstructor
public?class?AllArgsConstructorDemo?{
????private?long?id;
????private?String?name;
????private?int?age;
}
以上代碼經過 Lombok 編譯后,會生成如下代碼:
package?com.semlinker.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;
????}
}
@RequiredArgsConstructorDemo 注解
使用 @RequiredArgsConstructor 注解可以為指定類必須初始化的成員變量,如 final 成員變量,生成對應的構造函數,@RequiredArgsConstructor 注解的定義如下:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.SOURCE)
public?@interface?RequiredArgsConstructor?{
??//?若設置該屬性,將會生成一個私有的構造函數且生成一個staticName指定的靜態方法
????String?staticName()?default?"";
????AnyAnnotation[]?onConstructor()?default?{};
??//?設置生成構造函數的訪問級別,默認是public
????AccessLevel?access()?default?lombok.AccessLevel.PUBLIC;
}
示例
package?com.semlinker.lombok;@RequiredArgsConstructor
public?class?RequiredArgsConstructorDemo?{
????private?final?long?id;
????private?String?name;
????private?int?age;
}
以上代碼經過 Lombok 編譯后,會生成如下代碼:
package?com.semlinker.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?{};
??//?標識在執行字段計算前,是否調用父類的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?"";
????}
}
示例
package?com.semlinker.lombok;@EqualsAndHashCode
public?class?EqualsAndHashCodeDemo?{
????String?firstName;
????String?lastName;
????LocalDate?dateOfBirth;
}
以上代碼經過 Lombok 編譯后,會生成如下代碼:
package?com.semlinker.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?{
??//?打印輸出時是否包含字段的名稱
????boolean?includeFieldNames()?default?true;
??//?列出打印輸出時,需要排除的字段列表
????String[]?exclude()?default?{};
??//?顯式的列出需要打印輸出的字段列表
????String[]?of()?default?{};
??//?打印輸出的結果中是否包含父類的toString方法的返回結果
????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?"";
????}
}
示例
package?com.semlinker.lombok;@ToString(exclude?=?{"dateOfBirth"})
public?class?ToStringDemo?{
????String?firstName;
????String?lastName;
????LocalDate?dateOfBirth;
}
以上代碼經過 Lombok 編譯后,會生成如下代碼:
package?com.semlinker.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 注解與同時使用以下的注解的效果是一樣的:
@ToString
@Getter
@Setter
@RequiredArgsConstructor
@EqualsAndHashCode
@Data 注解的定義如下:
@Target(ElementType.TYPE)@Retention(RetentionPolicy.SOURCE)
public?@interface?Data?{
????String?staticConstructor()?default?"";
}
示例
package?com.semlinker.lombok;@Data
public?class?DataDemo?{
????private?Long?id;
????private?String?summary;
????private?String?description;
}
以上代碼經過 Lombok 編譯后,會生成如下代碼:
package?com.semlinker.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 的變體放在類上(適用于你所使用的日志記錄系統的任何一種);之后,你將擁有一個靜態的 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 一樣,該注解只能應用在靜態和實例方法上。它的操作類似于 synchronized 關鍵字,但是它鎖定在不同的對象上。synchronized 關鍵字應用在實例方法時,鎖定的是 this 對象,而應用在靜態方法上鎖定的是類對象。
對于 @Synchronized 注解聲明的方法來說,它鎖定的是?$LOCK?或?$lock。@Synchronized 注解的定義如下:
@Target(ElementType.METHOD)@Retention(RetentionPolicy.SOURCE)
public?@interface?Synchronized?{
??//?指定鎖定的字段名稱
????String?value()?default?"";
}
示例
package?com.semlinker.lombok;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");
????}
}
以上代碼經過 Lombok 編譯后,會生成如下代碼:
package?com.semlinker.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 注解可以為指定類實現建造者模式,該注解可以放在類、構造函數或方法上。@Builder 注解的定義如下:
@Target({TYPE,?METHOD,?CONSTRUCTOR})@Retention(SOURCE)
public?@interface?Builder?{
????@Target(FIELD)
????@Retention(SOURCE)
????public?@interface?Default?{}
??//?創建新的builder實例的方法名稱
????String?builderMethodName()?default?"builder";
????//?創建Builder注解類對應實例的方法名稱
????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;
????}
}
示例
package?com.semlinker.lombok;@Builder
public?class?BuilderDemo?{
????private?final?String?firstname;
????private?final?String?lastname;
????private?final?String?email;
}
以上代碼經過 Lombok 編譯后,會生成如下代碼:
package?com.semlinker.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 注解用于自動拋出已檢查的異常,而無需在方法中使用 throw 語句顯式拋出。@SneakyThrows 注解的定義如下:
@Target({ElementType.METHOD,?ElementType.CONSTRUCTOR})@Retention(RetentionPolicy.SOURCE)
public?@interface?SneakyThrows?{
????//?設置你希望向上拋的異常類
????Class?extends?Throwable>[]?value()?default?java.lang.Throwable.class;
}
示例
package?com.semlinker.lombok;public?class?SneakyThrowsDemo?{
????@SneakyThrows
????@Override
????protected?Object?clone()?{
????????return?super.clone();
????}
}
以上代碼經過 Lombok 編譯后,會生成如下代碼:
package?com.semlinker.lombok;public?class?SneakyThrowsDemo?{
????public?SneakyThrowsDemo()?{
????}
????protected?Object?clone()?{
????????try?{
????????????return?super.clone();
????????}?catch?(Throwable?var2)?{
????????????throw?var2;
????????}
????}
}
3.10 @NonNull 注解
你可以在方法或構造函數的參數上使用 @NonNull 注解,它將會為你自動生成非空校驗語句。@NonNull 注解的定義如下:
@Target({ElementType.FIELD,?ElementType.METHOD,?ElementType.PARAMETER,?ElementType.LOCAL_VARIABLE,?ElementType.TYPE_USE})@Retention(RetentionPolicy.CLASS)
@Documented
public?@interface?NonNull?{
}
示例
package?com.semlinker.lombok;public?class?NonNullDemo?{
????@Getter
????@Setter
????@NonNull
????private?String?name;
}
以上代碼經過 Lombok 編譯后,會生成如下代碼:
package?com.semlinker.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 注解用于自動管理資源,用在局部變量之前,在當前變量范圍內即將執行完畢退出之前會自動清理資源,自動生成 try-finally 這樣的代碼來關閉流。
@Target(ElementType.LOCAL_VARIABLE)@Retention(RetentionPolicy.SOURCE)
public?@interface?Cleanup?{
??//?設置用于執行資源清理/回收的方法名稱,對應方法不能包含任何參數,默認名稱為close。
????String?value()?default?"close";
}
示例
package?com.semlinker.lombok;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);
????????}
????}
}
以上代碼經過 Lombok 編譯后,會生成如下代碼:
package?com.semlinker.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 注解
在類的字段上應用 @With 注解之后,將會自動生成一個 withFieldName(newValue) 的方法,該方法會基于 newValue 調用相應構造函數,創建一個當前類對應的實例。@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;
????}
}
以上代碼經過 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 用在局部變量前面,相當于將變量聲明為 final,此外 Lombok 在編譯時還會自動進行類型推斷。val 的使用示例:
public?class?ValExample?{??public?String?example()?{
????val?example?=?new?ArrayList();
????example.add("Hello,?World!");
????val?foo?=?example.get(0);return?foo.toLowerCase();
??}public?void?example2()?{
????val?map?=?new?HashMap();map.put(0,?"zero");map.put(5,?"five");for?(val?entry?:?map.entrySet())?{
??????System.out.printf("%d:?%s\n",?entry.getKey(),?entry.getValue());
????}
??}
}
以上代碼等價于:
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?HashMapString>?map?=?new?HashMapString>();
????map.put(0,?"zero");
????map.put(5,?"five");for?(final?Map.EntryString>?entry?:?map.entrySet())?{
??????System.out.printf("%d:?%s\n",?entry.getKey(),?entry.getValue());
????}
??}
}
至此功能強大的 Lombok 工具就介紹完了。若你對于它的實現原理感興趣的話,建議閱讀:
https://www.jianshu.com/p/63038c7c515a
示例項目地址:
https://github.com/semlinker/springstack/tree/master/springboot2-lombok
四、參考資源
https://projectlombok.org/
https://interviewbubble.com/lombok-cheatsheet/
http://blog.didispace.com/java-lombok-how-to-use/
END
Java面試題專欄
【01期】Spring,SpringMVC,SpringBoot,SpringCloud有什么區別和聯系?
【02期】你能說說Spring框架中Bean的生命周期嗎?
【03期】如何決定使用 HashMap 還是 TreeMap?
【04期】分庫分表之后,id 主鍵如何處理?
【05期】消息隊列中,如何保證消息的順序性?
【06期】單例模式有幾種寫法?
【07期】Redis中是如何實現分布式鎖的?
【08期】說說Object類下面有幾種方法呢?
【09期】說說hashCode() 和 equals() 之間的關系?
【10期】Redis 面試常見問答
我知道你 “在看”
總結
以上是生活随笔為你收集整理的java: 程序包lombok不存在_Java开发神器:Lombok 学习指南的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 摩尔庄园冰川虾怎么钓
- 下一篇: 台达plc控制伺服电机编程实例_PLC控