Eclipse中安裝lombok安裝及使用和原理
lombok:通過註解方式減少POJO類的getter和setter等方法來消除冗餘程式碼量
安裝
1.下載 lombok.jar
2.官網說是可以雙擊安裝,,,我用這種方法不可行
2.手動安裝
(1)將lombok.jar移到eclipse的安裝目錄
(2)在eclipse.in檔案最後加入下面兩行
-Xbootclasspath/a:lombok.jar
-javaagent:lombok.jar
- =============
-javaagent:xxx.jar 的jar名稱 需要與根目錄下的jar名一致,
不一致,可能會出現eclipse無法啟動的情況。
(3)重啟eclipse,進行程式碼測試
原始java程式碼:
public class NoteTest {
private int noteId;
private String title;
private String content;
private int typeId;
}
class檔案反編譯後:
public class NoteTest { private int noteId; private String title; private String content; private int typeId; public NoteTest() {
、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
加入lombok註解後的java程式碼:
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString(exclude="typeId")
public class NoteTest {
private int noteId;
private String title;
private String content;
private int typeId;
}
加註解,經反編譯:
public class NoteTest { private int noteId; private String title; private String content; private int typeId; public int getNoteId() { return noteId; } public String getTitle() { return title; } public String getContent() { return content; } public int getTypeId() { return typeId; } public void setNoteId(int noteId) { this.noteId = noteId; } public void setTitle(String title) { this.title = title; } public void setContent(String content) { this.content = content; } public void setTypeId(int typeId) { this.typeId = typeId; } public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof NoteTest)) return false; NoteTest other = (NoteTest)o; if (!other.canEqual(this)) return false; if (getNoteId() != other.getNoteId()) return false; Object this$title = getTitle(); Object other$title = other.getTitle(); if (this$title != null ? !this$title.equals(other$title) : other$title != null) return false; Object this$content = getContent(); Object other$content = other.getContent(); if (this$content != null ? !this$content.equals(other$content) : other$content != null) return false; return getTypeId() == other.getTypeId(); } protected boolean canEqual(Object other) { return other instanceof NoteTest; } public int hashCode() { int PRIME = 59; int result = 1; result = result * 59 + getNoteId(); Object $title = getTitle(); result = result * 59 + ($title != null ? $title.hashCode() : 43); Object $content = getContent(); result = result * 59 + ($content != null ? $content.hashCode() : 43); result = result * 59 + getTypeId(); return result; } public NoteTest() { } public NoteTest(int noteId, String title, String content, int typeId) { this.noteId = noteId; this.title = title; this.content = content; this.typeId = typeId; } public String toString() { return (new StringBuilder("NoteTest(noteId=")).append(getNoteId()).append(", title=").append(getTitle()).append(", content=").append(getContent()).append(")").toString(); } }
常用的 lombok 註解
@EqualsAndHashCode:實現equals()方法和hashCode()方法 @ToString:實現toString()方法
@Data :註解在類上;提供類所有屬性的 getting 和 setting 方法,此外還提供了equals、canEqual、hashCode、toString 方法
@Setter:註解在屬性上;為屬性提供 setting 方法
@Getter:註解在屬性上;為屬性提供 getting 方法
@Log4j :註解在類上;為類提供一個 屬性名為log 的 log4j 日誌物件
@NoArgsConstructor:註解在類上;為類提供一個無參的構造方法
@AllArgsConstructor:註解在類上;為類提供一個全參的構造方法
@Cleanup:關閉流 @Synchronized:物件同步 @SneakyThrows:丟擲異常
@Data
不使用 lombok 的方案
public class Person {
private String id;
private String name;
private String identity;
private Logger log = Logger.getLogger(Person.class);
public Person() {
}
public Person(String id, String name, String identity) {
this.id = id;
this.name = name;
this.identity = identity;
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getIdentity() {
return identity;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setIdentity(String identity) {
this.identity = identity;
}
}
使用 lombok 的方案
@Data
@Log4j
@NoArgsConstructor
@AllArgsConstructor
public class Person {
private String id;
private String name;
private String identity;
}
上面的兩個 java 類,從作用上來看,它們的效果是一樣的,相比較之下,很明顯,使用 lombok 要簡潔許多
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
@Builder
不使用 lombok 的方案
public class Example<T> {
private T foo;
private final String bar;
private Example(T foo, String bar) {
this.foo = foo;
this.bar = bar;
}
public static <T> ExampleBuilder<T> builder() {
return new ExampleBuilder<T>();
}
public static class ExampleBuilder<T> {
private T foo;
private String bar;
private ExampleBuilder() {}
public ExampleBuilder foo(T foo) {
this.foo = foo;
return this;
}
public ExampleBuilder bar(String bar) {
this.bar = bar;
return this;
}
@java.lang.Override
public String toString() {
return "ExampleBuilder(foo = " + foo + ", bar = " + bar + ")";
}
public Example build() {
return new Example(foo, bar);
}
}
}
使用 lombok 的方案 guava 16.0.1
@Builder
public class Example {
private int foo;
private final String bar;
}
構造一個例項,屬性不需要單獨set
Example.builder().foo(1).bar(“test”).build()
lombok的使用和原理
一、專案背景
在寫Java程式的時候經常會遇到如下情形:
新建了一個Class類,然後在其中設定了幾個欄位,最後還需要花費很多時間來建立getter和setter方法
lombok專案的產生就是為了省去我們手動建立getter和setter方法的麻煩,它能夠在我們編譯原始碼的時候自動幫我們生成getter和setter方法。即它最終能夠達到的效果是:在原始碼中沒有getter和setter方法,但是在編譯生成的位元組碼檔案中有getter和setter方法
比如原始碼檔案:
-
import java.io.Serializable;
-
import lombok.Data;
-
@Data
-
public class BasicClusterInfo implements Serializable {
-
private static final long serialVersionUID = 3478135817352393604L;
-
private String hbaseKey;
-
private int receiverCount;
-
}
以下是編譯上述原始碼檔案得到的位元組碼檔案,對其反編譯得到的結果
-
public class BasicClusterInfo extends java.lang.Object implements java.io.Serializable{
-
public BasicClusterInfo();
-
public java.lang.String getHbaseKey();
-
public int getReceiverCount();
-
public void setHbaseKey(java.lang.String);
-
public void setReceiverCount(int);
-
public boolean equals(java.lang.Object);
-
public boolean canEqual(java.lang.Object);
-
public int hashCode();
-
public java.lang.String toString();
-
}
二、使用方法
使用lombok專案的方法很簡單,分為四個步驟:
1)在需要自動生成getter和setter方法的類上,加上@Data註解
2)在編譯類路徑中加入lombok.jar包
3)使用支援lombok的編譯工具編譯原始碼(關於支援lombok的編譯工具,見“四、支援lombok的編譯工具”)
4)編譯得到的位元組碼檔案中自動生成了getter和setter方法
三、原理分析
接下來進行lombok能夠工作的原理分析,以Oracle的javac編譯工具為例。
自從Java 6起,javac就支援“JSR 269 Pluggable Annotation Processing API”規範,只要程式實現了該API,就能在javac執行的時候得到呼叫。
舉例來說,現在有一個實現了"JSR 269 API"的程式A,那麼使用javac編譯原始碼的時候具體流程如下:
1)javac對原始碼進行分析,生成一棵抽象語法樹(AST)
2)執行過程中呼叫實現了"JSR 269 API"的A程式
3)此時A程式就可以完成它自己的邏輯,包括修改第一步驟得到的抽象語法樹(AST)
4)javac使用修改後的抽象語法樹(AST)生成位元組碼檔案
詳細的流程圖如下:
lombok本質上就是這樣的一個實現了"JSR 269 API"的程式。在使用javac的過程中,它產生作用的具體流程如下:
1)javac對原始碼進行分析,生成一棵抽象語法樹(AST)
2)執行過程中呼叫實現了"JSR 269 API"的lombok程式
3)此時lombok就對第一步驟得到的AST進行處理,找到@Data註解所在類對應的語法樹(AST),然後修改該語法樹(AST),增加getter和setter方法定義的相應樹節點
4)javac使用修改後的抽象語法樹(AST)生成位元組碼檔案
四、支援lombok的編譯工具
1)由“三、原理分析”可知,Oracle javac直接支援lombok
2)常用的專案管理工具Maven所使用的java編譯工具來源於配置的第三方工具,如果我們配置這個第三方工具為Oracle javac的話,那麼Maven也就直接支援lombok了
3)Intellij Idea配置的編譯工具為Oracle javac的話,也就直接支援lombok了。
4)Eclipse中使用的不是Oracle javac這個編譯工具,而是自己實現的Eclipse Compiler for Java (ECJ).要想使ECJ支援lombok,得進行設定,具體是在Eclipse程式目錄中的eclipse.ini檔案中新增如下兩行設定:
-javaagent:[lombok.jar所在路徑]
-Xbootclasspath/a:[lombok.jar所在路徑]
五、其他問題
現在使用Intellij Idea作為Java專案的IDE,配置Oracle javac作為編譯工具。
現在有一個A類,其中有一些欄位,沒有建立它們的setter和getter方法,使用了lombok的@Data註解,另外有一個B類,它呼叫了A類例項的相應欄位的setter和getter方法
編譯A類和B類所在的專案,並不會報錯,因為最終生成的A類位元組碼檔案中存在相應欄位的setter和getter方法
但是,IDE發現B類原始碼中所使用的A類例項的setter和getter方法在A類原始碼中找不到定義,IDE會認為這是錯誤
要解決以上這個不是真正錯誤的錯誤,可以下載安裝Intellij Idea中的"Lombok plugin"。
六、lombok的罪惡
使用lombok雖然能夠省去手動建立setter和getter方法的麻煩,但是卻大大降低了原始碼檔案的可讀性和完整性,降低了閱讀原始碼的舒適度。 這個根據自己的情況,來決定是否使用lombok
參考文獻:
[1]http://stackoverflow.com/questions/6107197/how-does-lombok-work
[2]https://projectlombok.org/download.html
[3]http://stackoverflow.com/questions/3061654/what-is-the-difference-between-javac-and-the-eclipse-compiler
[4]http://www.ibm.com/developerworks/library/j-lombok/
[5]http://notatube.blogspot.com/2010/12/project-lombok-creating-custom.html