1、基本注解
@Data:
- 所有屬性的get和set方法
- toString 方法
- hashCode方法
- equals方法
@Setter/@Getter
- 注解在屬性上,為單個屬性提供set/get方法
- 注解在類上,為該類所有屬性都提供set/get方法,都提供預設構造方法
@AllArgsConstructor
- 注解在
上,提供全參的構造方法,加了這個注解後,類中不提供預設構造方法類
@NoArgsConstructor
- 注解在 類上;為類提供一個無參的構造方法
@EqualsAndHashCode
- 注解在
上, 可以生成 equals、canEqual、hashCode 方法類
public class LomBokData {
public LomBokData() {
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof LomBokData)) {//判斷object是否是某個類
return false;
} else {
LomBokData other = (LomBokData)o;
return other.canEqual(this);
}
}
protected boolean canEqual(Object other) { //隻能判别是否屬于同一種類對象
return other instanceof LomBokData;
}
public int hashCode() {
int result = 1;
return result;
}
}
@NonNull
- 注解在
上,會自動産生一個關于此參數的非空校驗。如果參數為空,則抛出一個空指針的異常,也會有一個預設的無參構造方法屬性
2、@Builder 實戰使用
@Builder
注釋為你的類生成相對略微複雜的建構器API。
@Builder
可以讓你以下面顯示的那樣調用你的代碼,來初始化你的執行個體對象
Person.builder()
.name("Adam Savage")
.city("San Francisco")
.job("Mythbusters")
.job("Unchained Reaction")
.build();
@Builder可以放在類,構造函數或方法上。 雖然放在類上和放在構造函數上這兩種模式是最常見的用例,但@Builder最容易用放在方法的用例來解釋。
使用@Builder注釋的方法可以幫助我們完成一下一些事情:
- 一個名為FooBuilder的内部靜态類,并具有和實體類形同的屬性(稱為建構器)。
- 在建構器中:對于目标類中的所有的屬性和未初始化的final字段,都會在建構器中建立對應屬性;
- 在建構器中:建立一個無參的default構造函數。
- 在建構器中:對于實體類中的每個參數,都會對應建立類似于“setter”的方法,隻不多方法名與該參數名相同。 并且傳回值是建構器本身(便于鍊式調用),如上例所示。
- 在建構器中:一個build()方法,調用此方法,就會根據設定的值進行建立實體對象。
- 在建構器中:同時也會生成一個toString()方法。
- 在實體類中:會建立一個builder()方法,它的目的是用來建立建構器。
@Builder
public class User {
private String username;
private String password;
}
// 編譯後:
public class User {
private String username;
private String password;
User(String username, String password) {
this.username = username; this.password = password;
}
public static User.UserBuilder builder() {
return new User.UserBuilder();
}
public static class UserBuilder {
private String username;
private String password;
UserBuilder() {}
public User.UserBuilder username(String username) {
this.username = username;
return this;
}
public User.UserBuilder password(String password) {
this.password = password;
return this;
}
public User build() {
return new User(this.username, this.password);
}
public String toString() {
return "User.UserBuilder(username=" + this.username + ", password=" + this.password + ")";
}
}
}
3. @Builder 中使用 @Singular 注釋集合
2.1 @Singular 實戰使用
@Builder
也可以為集合類型的參數或字段生成一種特殊的方法。 它采用修改清單中一個元素而不是整個清單的方式,可以是增加一個元素,也可以是删除一個元素。 例如:
Person.builder()
.job("Mythbusters")
.job("Unchained Reaction")
.build();
這樣就可以輕松地将List <String>字段中包含2個字元串。 但是想要這樣來操作集合,你需要使用@Singular來注釋字段或參數。
在使用@Singular注釋注釋一個集合字段(使用@Builder注釋類),lombok會将該建構器節點視為一個集合,并生成兩個adder方法而不是setter方法
- 一個向集合添加單個元素,
- 一個将另一個集合的所有元素添加到集合中
将不生成僅設定集合(替換已添加的任何内容)的setter。 還生成了
clear
方法。 這些
singular
建構器相對而言是有些複雜的,主要是來保證以下特性:
- 在調用
時,生成的集合将是不可變的。build()
- 在調用
之後調用其中一個build()
方法或adder
方法不會修改任何已經生成的對象。如果對集合修改之後,再調用clear
,則會建立一個基于上一個對象建立的對象實體。build()
- 生成的集合将被壓縮到最小的可行格式,同時保持高效
@Singular隻能應用于lombok已知的集合類型。目前,支援的類型有:
- java.util:
- Iterable, Collection, 和List (一般情況下,由壓縮的不可修改的ArrayList支援).
- Set, SortedSet, and NavigableSet (一般情況下,生成可變大小不可修改的HashSet或者TreeSet).
- Map, SortedMap, and NavigableMap (一般情況下,生成可變大小不可修改的HashMap或者TreeMap).
- Guava’s com.google.common.collect:
- ImmutableCollection and ImmutableList
- ImmutableSet and ImmutableSortedSet
- ImmutableMap, ImmutableBiMap, and ImmutableSortedMap
- ImmutableTable
@Builder
public class User {
private final Integer id;
private final String zipCode = "215500";
private String username;
private String password;
@Singular
private List<String> hobbies;
}
// 編譯後:
public class User {
private final Integer id;
private final String zipCode = "215500";
private String username;
private String password;
private List<String> hobbies;
User(Integer id, String username, String password, List<String> hobbies) {
this.id = id; this.username = username;
this.password = password; this.hobbies = hobbies;
}
public static User.UserBuilder builder() {return new User.UserBuilder();}
public static class UserBuilder {
private Integer id;
private String username;
private String password;
private ArrayList<String> hobbies;
UserBuilder() {}
public User.UserBuilder id(Integer id) { this.id = id; return this; }
public User.UserBuilder username(String username) { this.username = username; return this; }
public User.UserBuilder password(String password) { this.password = password; return this; }
public User.UserBuilder hobby(String hobby) {
if (this.hobbies == null) {
this.hobbies = new ArrayList();
}
this.hobbies.add(hobby);
return this;
}
public User.UserBuilder hobbies(Collection<? extends String> hobbies) {
if (this.hobbies == null) {
this.hobbies = new ArrayList();
}
this.hobbies.addAll(hobbies);
return this;
}
public User.UserBuilder clearHobbies() {
if (this.hobbies != null) {
this.hobbies.clear();
}
return this;
}
public User build() {
List hobbies;
switch(this.hobbies == null ? 0 : this.hobbies.size()) {
case 0:
hobbies = Collections.emptyList();
break;
case 1:
hobbies = Collections.singletonList(this.hobbies.get(0));
break;
default:
hobbies = Collections.unmodifiableList(new ArrayList(this.hobbies));
}
return new User(this.id, this.username, this.password, hobbies);
}
public String toString() {
return "User.UserBuilder(id=" + this.id + ", username=" + this.username + ", password=" + this.password + ", hobbies=" + this.hobbies + ")";
}
}
}
其實,lombok的創作者還是很用心的,在進行build()來床建執行個體對象時,并沒有直接使用
Collections.unmodifiableList(Collection)
此方法來床架執行個體,而是分為三種情況
- 第一種,當集合中沒有元素時,建立一個空list;
- 第二種情況,當集合中存在一個元素時,建立一個不可變的單元素list;
- 第三種情況,根據目前集合的元素數量建立對應合适大小的list;
當然我們看編譯生成的代碼,建立了三個關于集合操作的方法:
-
:向集合中添加一個元素hobby(String hobby)
-
:添加一個集合所有的元素hobbies(Collection<? extends String> hobbies)
-
:清空目前集合資料clearHobbies()
2.2 @Singular 注解配置詳解
@Target({FIELD, PARAMETER})
@Retention(SOURCE)
public @interface Singular {
// 修改添加集合元素的方法名
String value() default "";
}
- 測試如何使用注解屬性
vlaue
@Builder
public class User {
private final Integer id;
private final String zipCode = "215500";
private String username;
private String password;
@Singular(value = "testHobbies")
private List<String> hobbies;
}
// 測試類
public class BuilderTest {
public static void main(String[] args) {
User user = User.builder()
.testHobbies("reading")
.testHobbies("chatting")
.id(1)
.password("jdkong")
.username("jdkong")
.build();
System.out.println(user);
}
}
說明,當我們使用了注解屬性
value
之後,我們在使用添加集合元素時的方法名發生相應的改變。但是,同時生成的添加整個集合的方法名發生改變了嗎?我們再來看看編譯後的代碼:
// 編譯後:
public class User {
// 省略部分代碼,隻看關鍵部分
public static class UserBuilder {
public User.UserBuilder testHobbies(String testHobbies) {
if (this.hobbies == null) {
this.hobbies = new ArrayList();
}
this.hobbies.add(testHobbies);
return this;
}
public User.UserBuilder hobbies(Collection<? extends String> hobbies) {
if (this.hobbies == null) {
this.hobbies = new ArrayList();
}
this.hobbies.addAll(hobbies);
return this;
}
public User.UserBuilder clearHobbies() {
if (this.hobbies != null) {
this.hobbies.clear();
}
return this;
}
}
}
可以看到,隻有添加一個元素的方法名發生了改變。
4. @Builder.Default 使用
比如有這樣一個實體類:
@Builder
@ToString
public class User {
@Builder.Default
private final String id = UUID.randomUUID().toString();
private String username;
private String password;
@Builder.Default
private long insertTime = System.currentTimeMillis();
}
在類中我在
id
和
insertTime
上都添加注解
@Builder.Default
,當我在使用這個實體對象時,我就不需要在為這兩個字段進行初始化值,如下面這樣:
public class BuilderTest {
public static void main(String[] args) {
User user = User.builder()
.password("jdkong")
.username("jdkong")
.build();
System.out.println(user);
}
}
// 輸出内容:
User(id=416219e1-bc64-43fd-b2c3-9f8dc109c2e8, username=jdkong, password=jdkong, insertTime=1546869309868)
lombok
在執行個體化對象時就為我們初始化了這兩個字段值。
當然,你如果再對這兩個字段進行設值的話,那麼預設定義的值将會被覆寫掉,如下面這樣:
public class BuilderTest {
public static void main(String[] args) {
User user = User.builder()
.id("jdkong")
.password("jdkong")
.username("jdkong")
.build();
System.out.println(user);
}
}
// 輸出内容
User(id=jdkong, username=jdkong, password=jdkong, insertTime=1546869642151)
5. @Builder 詳細配置
下面我們再來詳細看看
@Builder
這個注解類地詳細實作:
@Target({TYPE, METHOD, CONSTRUCTOR})
@Retention(SOURCE)
public @interface Builder {
// 如果@Builder注解在類上,可以使用 @Builder.Default指定初始化表達式
@Target(FIELD)
@Retention(SOURCE)
public @interface Default {}
// 指定實體類中建立 Builder 的方法的名稱,預設為: builder (個人覺得沒必要修改)
String builderMethodName() default "builder";
// 指定 Builder 中用來構件實體類的方法的名稱,預設為:build (個人覺得沒必要修改)
String buildMethodName() default "build";
// 指定建立的建造者類的名稱,預設為:實體類名+Builder
String builderClassName() default "";
// 使用toBuilder可以實作以一個執行個體為基礎繼續建立一個對象。(也就是重用原來對象的值)
boolean toBuilder() default false;
@Target({FIELD, PARAMETER})
@Retention(SOURCE)
public @interface ObtainVia {
// 告訴lombok使用表達式擷取值
String field() default "";
// 告訴lombok使用表達式擷取值
String method() default "";
boolean isStatic() default false;
}
}
以上注解屬性,我隻測試一個比較常用的toBuilder,因為我們在對實體對象進行操作時,往往會存在對某些實體對象的某個字段進行二次指派,這個時候就會用到這一屬性。但是,這會建立一個新的對象,而不是原來的對象,原來的對象屬性是不可變的,除非你自己想要給這個實體類再添加上@Data或者@setter方法(我是這麼幹過,哈哈)。下面就來測試一下:
@Builder(toBuilder = true)
@ToString
public class User {
private String username;
private String password;
}
// 測試類
public class BuilderTest {
public static void main(String[] args) {
User user1 = User.builder()
.password("jdkong")
.username("jdkong")
.build();
System.out.println(user1);
User user2 = user1.toBuilder().username("jdkong2").build();
// 驗證user2是否是基于user1的現有屬性建立的
System.out.println(user2);
// 驗證對象是否是同一對象
System.out.println(user1 == user2);
}
}
// 輸出内容
User(username=jdkong, password=jdkong)
User(username=jdkong2, password=jdkong)
false
6. @Builder 全局配置
# 是否禁止使用@Builder
lombok.builder.flagUsage = [warning | error] (default: not set)
#是否使用Guaua
lombok.singular.useGuava = [true | false] (default: false)
# 是否自動使用singular,預設是使用
lombok.singular.auto = [true | false] (default: true)