前言
what?你的 Java 代碼中還充斥著大量的 set/get 方法丧慈?
我們?cè)趧傞_始學(xué)習(xí) Java 語(yǔ)言的時(shí)候講過(guò)析命,面向?qū)ο蟮娜筇卣骶褪欠庋b,繼承逃默,和多態(tài)鹃愤。在 Java 中,要保證封裝性完域,需要將成員變量私有化昼浦,對(duì)外提供 set/get 方法來(lái)訪問(wèn),雖然現(xiàn)在的 IDE筒主,像 eclipse关噪,IDEA都提供了快捷鍵鸟蟹,來(lái)生成 set/get 方法,但是在做項(xiàng)目的時(shí)候使兔,一個(gè) JavaBean 往往會(huì)有很多的成員變量建钥,一個(gè)變量對(duì)應(yīng)兩個(gè)方法,如果有10幾個(gè)成員變量虐沥,那么會(huì)對(duì)應(yīng)20多個(gè)方法熊经,也許還要去寫構(gòu)造器、equals 等方法欲险,而且需要維護(hù)镐依。這樣一來(lái),會(huì)使代碼變得非常冗余天试,這些顯得很冗長(zhǎng)也沒(méi)有太多技術(shù)含量槐壳,一旦修改屬性,就容易出現(xiàn)忘記修改對(duì)應(yīng)方法的失誤喜每。
我在看大佬的項(xiàng)目的源碼的時(shí)候务唐,看到他們的代碼中都沒(méi)有 set/get 方法,取而代之的是在 JavaBean 上標(biāo)注的注解带兜,我感到非常的好奇枫笛,原來(lái)他們是用了一種叫做 Lombok 的插件,便去詳細(xì)了解了這個(gè)插件刚照。
Lombok背景介紹
官方介紹如下:
Project Lombok makes java a spicier language by adding 'handlers' that know how to build and compile simple, boilerplate-free, not-quite-java code.
大致意思是 Lombok 通過(guò)增加一些“處理程序”刑巧,可以讓 Java 變得簡(jiǎn)潔、快速无畔。
Lombok使用方法
Lombok 能通過(guò)注解的方式海诲,在編譯時(shí)自動(dòng)為屬性生成構(gòu)造器、getter/setter檩互、equals特幔、hashcode、toString 方法闸昨。出現(xiàn)的神奇就是在源碼中沒(méi)有 getter 和 setter 方法蚯斯,但是在編譯生成的字節(jié)碼文件中有 getter 和 setter 方法。這樣就省去了手動(dòng)重建這些代碼的麻煩饵较,使代碼看起來(lái)更簡(jiǎn)潔些拍嵌。
Lombok 的使用跟引用 jar 包一樣,可以在官網(wǎng)(https://projectlombok.org/download)下載 jar 包循诉,也可以使用 maven 添加依賴:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
注意:
第一次使用 Lombok 插件需要做如下幾步配置
- 將 Lombok 插件安裝到 IDEA
file -> setting
選中 Plugins横辆,搜索 Lombok,點(diǎn)擊 Install
選擇默認(rèn)的編譯方式為 javac茄猫,因?yàn)?eclipse 是不支持 Lombok 的編譯方式的狈蚤,javac 支持 Lombok 的編譯方式困肩。
打開注解生成器 Enable annotation processing
再次注意:
IntelliJ IDEA 2019.2(也就是我用的版本)默認(rèn)是不支持 Lombok 插件的,需要去
https://plugins.jetbrains.com/plugin/6317-lombok/versions
下載對(duì)應(yīng)版本的插件脆侮,然后手動(dòng)引入锌畸,在 IDEA 中選擇 File -> Setting -> plugins 找到 Install Plugin from Disk…(注意版本不同位置可能有所差異)
接下來(lái)我們來(lái)分析 Lombok 中注解的具體用法
@Data
@Data 注解在類上,會(huì)為類的所有屬性自動(dòng)生成 setter/getter靖避、equals潭枣、canEqual、hashCode幻捏、toString 方法盆犁,如為 final 屬性,則不會(huì)為該屬性生成 setter 方法篡九。
比如我們寫一個(gè)學(xué)生類
@Data
public class Student {
private String name;
private Integer age;
private Integer id;
private String major;
}
這樣就可以調(diào)用 set/get 方法了谐岁。
@Getter/@Setter
如果覺得@Data 太過(guò)殘暴(因?yàn)锧Data 集合了@ToString、@EqualsAndHashCode瓮下、@Getter/@Setter翰铡、@RequiredArgsConstructor 的所有特性)不夠精細(xì)钝域,可以使用@Getter/@Setter 注解讽坏,此注解在屬性上,可以為相應(yīng)的屬性自動(dòng)生成 set/get 方法例证。
public class Student {
@Setter private String name;
private Integer age;
private Integer id;
private String major;
public static void main(String[] args) {
Student stu = new Student();
stu.setName("Mr.ml");
}
}
@NonNull
該注解用在屬性或構(gòu)造器上路呜,Lombok 會(huì)生成一個(gè)非空的聲明,可用于校驗(yàn)參數(shù)织咧,能幫助避免空指針胀葱。
public class Student {
@Setter private String name;
private Integer age;
private Integer id;
private String major;
public Student(@NonNull String name) {
this.name = name;
}
}
@Cleanup
該注解能幫助我們自動(dòng)調(diào)用 close() 方法,很大的簡(jiǎn)化了代碼笙蒙。
public class CleanupExample {
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);
}
}
}
@EqualsAndHashCode
默認(rèn)情況下抵屿,會(huì)使用所有非靜態(tài)(non-static)和非瞬態(tài)(non-transient)屬性來(lái)生成 equals 和 hashCode,也能通過(guò) exclude 注解來(lái)排除一些屬性捅位。
@EqualsAndHashCode(exclude={"id", "shape"})
public class EqualsAndHashCodeExample {
private transient int transientVar = 10;
private String name;
private double score;
private Shape shape = new Square(5, 10);
private String[] tags;
private int id;
public String getName() {
return this.name;
}
@EqualsAndHashCode(callSuper=true)
public static class Square extends Shape {
private final int width, height;
public Square(int width, int height) {
this.width = width;
this.height = height;
}
}
}
@ToString
類使用@ToString 注解轧葛,Lombok 會(huì)生成一個(gè) toString() 方法,默認(rèn)情況下艇搀,會(huì)輸出類名、所有屬性(會(huì)按照屬性定義順序),用逗號(hào)來(lái)分割州胳。
通過(guò)將 includeFieldNames 參數(shù)設(shè)為 true客峭,就能明確的輸出 toString() 屬性。這一點(diǎn)是不是有點(diǎn)繞口矩屁,通過(guò)代碼來(lái)看會(huì)更清晰些辟宗。
@ToString(exclude="id")
public class ToStringExample {
private static final int STATIC_VAR = 10;
private String name;
private Shape shape = new Square(5, 10);
private String[] tags;
private int id;
public String getName() {
return this.getName();
}
@ToString(callSuper=true, includeFieldNames=true)
public static class Square extends Shape {
private final int width, height;
public Square(int width, int height) {
this.width = width;
this.height = height;
}
}
}
@NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor
無(wú)參構(gòu)造器爵赵、部分參數(shù)構(gòu)造器、全參構(gòu)造器慢蜓。Lombok沒(méi)法實(shí)現(xiàn)多種參數(shù)構(gòu)造器的重載亚再。
@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class ConstructorExample<T> {
private int x, y;
@NonNull private T description;
@NoArgsConstructor
public static class NoArgsExample {
@NonNull private String field;
}
}