[Java]使用lombok提高編碼效率

天府雲創發表於2017-12-26

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.



github上官方是這麼描述lombok的:
         lombok專案通過增加處理程式使我們的java語言更加刺激(簡潔和快速)。


先看個簡單示例:

 
我們做java開發的時候,最不少寫的就是javabean了,bean欄位都需要新增gettter/setter方法,往往我們只能一次又一次的使用ide生成gettter,setter 構造器等等。

lombok是如何幫我們解決這種重複性勞動呢?

[java] view plain copy
  1. package com.lhy.boot.lombok;  
  2.   
  3. import lombok.Getter;  
  4. import lombok.Setter;  
  5.   
  6. @Getter  
  7. @Setter  
  8. public class GetterSetterExample1 {  
  9.   
  10.     private int age = 10;  
  11.       
  12.     private String name ="張三丰";  
  13.       
  14.     private boolean registerd;  
  15.       
  16.     private String sex;  
  17.   
  18. }  

編譯後的class:

[java] view plain copy
  1. package com.lhy.boot.lombok;  
  2.   
  3. public class GetterSetterExample1  
  4. {  
  5.   private int age = 10;  
  6.   
  7.   private String name = "張三丰";  
  8.   private boolean registerd;  
  9.   private String sex;  
  10.   
  11.   public int getAge()  
  12.   {  
  13.     return this.age;  
  14.   }  
  15.   
  16.   public String getName() {  
  17.     return this.name;  
  18.   }  
  19.   
  20.   public boolean isRegisterd() {  
  21.     return this.registerd;  
  22.   }  
  23.   
  24.   public String getSex() {  
  25.     return this.sex;  
  26.   }  
  27.   
  28.   public GetterSetterExample1 setAge(int age) {  
  29.     this.age = age;  
  30.     return this;  
  31.   }  
  32.   
  33.   public GetterSetterExample1 setName(String name) {  
  34.     this.name = name;  
  35.     return this;  
  36.   }  
  37.   
  38.   public GetterSetterExample1 setRegisterd(boolean registerd) {  
  39.     this.registerd = registerd;  
  40.     return this;  
  41.   }  
  42.   
  43.   public GetterSetterExample1 setSex(String sex) {  
  44.     this.sex = sex;  
  45.     return this;  
  46.   }  
  47. }  


通過gettter,setter註解lombok已經幫我們自動生成了getter,setter方法!

是不是很神奇呢?lombok是怎麼的做到的?這個後邊再講,先把lombok ide外掛環境搭起來

下載並引用

maven專案新增依賴

[html] view plain copy
  1. <dependency>  
  2.             <groupId>org.projectlombok</groupId>  
  3.             <artifactId>lombok</artifactId>  
  4.             <version>1.16.16</version>  
  5.         </dependency>  

或者到官網下載jar包 https://projectlombok.org/download

安裝ide外掛

myeclipse/eclipse

下載完成後 命令列執行 

[java] view plain copy
  1. java -jar lombok-1.16.16.jar  
彈出安裝介面:



specify location 選擇myeclipse安裝目錄,eclipse同理。

點選 install/update 安裝完成。


或者將jar包放入myeclipse 根目錄下

myeclipse.ini檔案末尾新增:

[java] view plain copy
  1. -javaagent:lombok-1.16.16.jar  
重啟myeclipse即可。

安裝完畢後

開啟myeclipse about 可以看到


證明外掛安裝完成


IntelliJ IDEA

  • 定位到 File > Settings > Plugins
  • 點選 Browse repositories…
  • 搜尋 Lombok Plugin
  • 點選 Install plugin
  • 重啟 IDEA

Lombok註解詳解

全域性配置檔案

我們可以從專案根目錄下新建一個lombok.config(當然目錄不是固定的,lombok會搜尋所有lombok.config檔案)
在這個檔案加入一行
config.stopBubbling = true 
表示該檔案目錄為根目錄,lombok將從該目錄下開始搜尋。
每個子目錄都可以配置lombok.config 作用範圍只在該目錄下,並且覆蓋父目錄的配置。


Lombok通常為所有生成的節點生成註釋,新增@javax.annotation.Generated 。

可以用:

lombok.addJavaxGeneratedAnnotation = false 設定取消



下面看下lombok提供了哪些有趣的註解。


1.@val @var

使用Lombok ,java也能夠像javascript一樣使用弱型別定義變數了

val註解變數申明是final型別 var註解變數是非final型別

[java] view plain copy
  1.  import java.util.ArrayList;  
  2. import java.util.HashMap;  
  3. import lombok.val;  
  4.   
  5. public class ValExample {  
  6.   public String example() {  
  7.     val example = new ArrayList<String>();  
  8.     example.add("Hello, World!");  
  9.     val foo = example.get(0);  
  10.     return foo.toLowerCase();  
  11.   }  
  12.     
  13.   public void example2() {  
  14.     val map = new HashMap<Integer, String>();  
  15.     map.put(0"zero");  
  16.     map.put(5"five");  
  17.     for (val entry : map.entrySet()) {  
  18.       System.out.printf("%d: %s\n", entry.getKey(), entry.getValue());  
  19.     }  
  20.   }  
  21. }  
翻譯後

[java] view plain copy
  1. <span style="font-weight:normal;">import java.util.ArrayList;  
  2. import java.util.HashMap;  
  3. import java.util.Map;  
  4.   
  5. public class ValExample {  
  6.   public String example() {  
  7.     final ArrayList<String> example = new ArrayList<String>();  
  8.     example.add("Hello, World!");  
  9.     final String foo = example.get(0);  
  10.     return foo.toLowerCase();  
  11.   }  
  12.     
  13.   public void example2() {  
  14.     final HashMap<Integer, String> map = new HashMap<Integer, String>();  
  15.     map.put(0"zero");  
  16.     map.put(5"five");  
  17.     for (final Map.Entry<Integer, String> entry : map.entrySet()) {  
  18.       System.out.printf("%d: %s\n", entry.getKey(), entry.getValue());  
  19.     }  
  20.   }  
  21. }</span>  

2.@NonNull

在方法或建構函式的引數上使用@NonNull,lombok將生成一個空值檢查語句。

[java] view plain copy
  1. <span style="font-weight:normal;"import lombok.NonNull;  
  2.   
  3. public class NonNullExample extends Something {  
  4.   private String name;  
  5.     
  6.   public NonNullExample(@NonNull Person person) {  
  7.     super("Hello");  
  8.     this.name = person.getName();  
  9.   }  
  10. }</span>  
翻譯後

[java] view plain copy
  1. <span style="font-weight:normal;">import lombok.NonNull;  
  2.   
  3. public class NonNullExample extends Something {  
  4.   private String name;  
  5.     
  6.   public NonNullExample(@NonNull Person person) {  
  7.     super("Hello");  
  8.     if (person == null) {  
  9.       throw new NullPointerException("person");  
  10.     }  
  11.     this.name = person.getName();  
  12.   }  
  13. }</span>  


3.@Cleanup

使用該註解能夠自動釋放io資源

[java] view plain copy
  1. <span style="font-weight:normal;"import lombok.Cleanup;  
  2. import java.io.*;  
  3.   
  4. public class CleanupExample {  
  5.   public static void main(String[] args) throws IOException {  
  6.     @Cleanup InputStream in = new FileInputStream(args[0]);  
  7.     @Cleanup OutputStream out = new FileOutputStream(args[1]);  
  8.     byte[] b = new byte[10000];  
  9.     while (true) {  
  10.       int r = in.read(b);  
  11.       if (r == -1break;  
  12.       out.write(b, 0, r);  
  13.     }  
  14.   }  
  15. }</span>  
翻譯後

[java] view plain copy
  1. <span style="font-weight:normal;">import java.io.*;  
  2.   
  3. public class CleanupExample {  
  4.   public static void main(String[] args) throws IOException {  
  5.     InputStream in = new FileInputStream(args[0]);  
  6.     try {  
  7.       OutputStream out = new FileOutputStream(args[1]);  
  8.       try {  
  9.         byte[] b = new byte[10000];  
  10.         while (true) {  
  11.           int r = in.read(b);  
  12.           if (r == -1break;  
  13.           out.write(b, 0, r);  
  14.         }  
  15.       } finally {  
  16.         if (out != null) {  
  17.           out.close();  
  18.         }  
  19.       }  
  20.     } finally {  
  21.       if (in != null) {  
  22.         in.close();  
  23.       }  
  24.     }  
  25.   }  
  26. }</span>  

當然從1.7開始jdk已經提供了try with resources的方式自動回收資源

[java] view plain copy
  1. static String readFirstLineFromFile(String path) throws IOException {  
  2.     try (BufferedReader br = new BufferedReader(new FileReader(path))) {  
  3.         return br.readLine();  
  4.     }  
  5. }  

4.@Getter/@Setter

[java] view plain copy
  1. <span style="font-weight:normal;">import lombok.AccessLevel;  
  2. import lombok.Getter;  
  3. import lombok.Setter;  
  4.   
  5. public class GetterSetterExample {  
  6.   /** 
  7.    * Age of the person. Water is wet. 
  8.    *  
  9.    * @param age New value for this person's age. Sky is blue. 
  10.    * @return The current value of this person's age. Circles are round. 
  11.    */  
  12.   @Getter @Setter private int age = 10;  
  13.     
  14.   /** 
  15.    * Name of the person. 
  16.    * -- SETTER -- 
  17.    * Changes the name of this person. 
  18.    *  
  19.    * @param name The new value. 
  20.    */  
  21.   @Setter(AccessLevel.PROTECTED) private String name;  
  22.     
  23.   @Override public String toString() {  
  24.     return String.format("%s (age: %d)", name, age);  
  25.   }  
  26. }</span>  
翻譯後
[java] view plain copy
  1. <span style="font-weight:normal;"public class GetterSetterExample {  
  2.   /** 
  3.    * Age of the person. Water is wet. 
  4.    */  
  5.   private int age = 10;  
  6.   
  7.   /** 
  8.    * Name of the person. 
  9.    */  
  10.   private String name;  
  11.     
  12.   @Override public String toString() {  
  13.     return String.format("%s (age: %d)", name, age);  
  14.   }  
  15.     
  16.   /** 
  17.    * Age of the person. Water is wet. 
  18.    * 
  19.    * @return The current value of this person's age. Circles are round. 
  20.    */  
  21.   public int getAge() {  
  22.     return age;  
  23.   }  
  24.     
  25.   /** 
  26.    * Age of the person. Water is wet. 
  27.    * 
  28.    * @param age New value for this person's age. Sky is blue. 
  29.    */  
  30.   public void setAge(int age) {  
  31.     this.age = age;  
  32.   }  
  33.     
  34.   /** 
  35.    * Changes the name of this person. 
  36.    * 
  37.    * @param name The new value. 
  38.    */  
  39.   protected void setName(String name) {  
  40.     this.name = name;  
  41.   }  
  42. }</span>  
擴充套件配置:
lombok.accessors.chain = [true | false] (default: false)如果設定為true,生成的setter將返回this(而不是void),通過這個配置我們可以像jquery一樣愉快的鏈式程式設計了。可以在類加增加一個@Accessors 註解 配置chain屬性,優先於全域性配置。
lombok.accessors.fluent = [true | false] (default: false)如果設定為true,生成的getter和setter將不會使用bean標準的get、is或set進行字首;相反,方法將使用與欄位相同的名稱(減去字首)。可以在類加增加一個@Accessors註解,配置fluent屬性,優先於全域性配置
lombok.accessors.prefix += a field prefix (default: empty list)給getter/setter方法增加字首 例如配置 +=M 原有的 getFoo方法將變為getMFoo方法。 lombok.getter.noIsPrefix = [true | false] (default: false)如果設定為true,那麼boolean型欄位生成的getter將使用get字首而不是預設的is字首


5.@ToString

生成一個toString方法,log debug神器

預設的toString格式為:ClassName(fieldName= fieleValue ,fieldName1=fieleValue)

[java] view plain copy
  1. <span style="font-weight:normal;">import lombok.ToString;  
  2.   
  3. @ToString(exclude="id")  
  4. public class ToStringExample {  
  5.   private static final int STATIC_VAR = 10;  
  6.   private String name;  
  7.   private Shape shape = new Square(510);  
  8.   private String[] tags;  
  9.   private int id;  
  10.     
  11.   public String getName() {  
  12.     return this.getName();  
  13.   }  
  14.     
  15.   @ToString(callSuper=true, includeFieldNames=true)  
  16.   public static class Square extends Shape {  
  17.     private final int width, height;  
  18.       
  19.     public Square(int width, int height) {  
  20.       this.width = width;  
  21.       this.height = height;  
  22.     }  
  23.   }  
  24. }</span>  
翻譯後
[java] view plain copy
  1. import java.util.Arrays;  
  2.   
  3. ublic class ToStringExample {  
  4.  private static final int STATIC_VAR = 10;  
  5.  private String name;  
  6.  private Shape shape = new Square(510);  
  7.  private String[] tags;  
  8.  private int id;  
  9.    
  10.  public String getName() {  
  11.    return this.getName();  
  12.  }  
  13.    
  14.  public static class Square extends Shape {  
  15.    private final int width, height;  
  16.      
  17.    public Square(int width, int height) {  
  18.      this.width = width;  
  19.      this.height = height;  
  20.    }  
  21.      
  22.    @Override public String toString() {  
  23.      return "Square(super=" + super.toString() + ", width=" + this.width + ", height=" + this.height + ")";  
  24.    }  
  25.  }  
  26.    
  27.  @Override public String toString() {  
  28.    return "ToStringExample(" + this.getName() + ", " + this.shape + ", " + Arrays.deepToString(this.tags) + ")";  
  29.  }  

擴充套件配置:

lombok.toString.includeFieldNames = [true | false] (default: true)

通常,lombok以fieldName=fieldValue的形式為每個欄位生成一個toString響應的片段。如果設定為false,lombok將省略欄位的名稱,可以在該註解上配置屬性includeFieldNames來標示包含的欄位,這樣可以覆蓋預設配置。

lombok.toString.doNotUseGetters = [true | false] (default: false)
如果設定為true,lombok將直接訪問欄位,而不是在生成tostring方法時使用getter(如果可用)。可以在該註解上配置屬性doNotUseGetters來標示不使用getter的欄位,這樣可以覆蓋預設配置。


6.@EqualsAndHashCode

給類增加equals和hashCode方法

[java] view plain copy
  1.  import lombok.EqualsAndHashCode;  
  2.   
  3. @EqualsAndHashCode(exclude={"id""shape"})  
  4. public class EqualsAndHashCodeExample {  
  5.   private transient int transientVar = 10;  
  6.   private String name;  
  7.   private double score;  
  8.   private Shape shape = new Square(510);  
  9.   private String[] tags;  
  10.   private int id;  
  11.     
  12.   public String getName() {  
  13.     return this.name;  
  14.   }  
  15.     
  16.   @EqualsAndHashCode(callSuper=true)  
  17.   public static class Square extends Shape {  
  18.     private final int width, height;  
  19.       
  20.     public Square(int width, int height) {  
  21.       this.width = width;  
  22.       this.height = height;  
  23.     }  
  24.   }  
  25. }  
翻譯後
[java] view plain copy
  1. import java.util.Arrays;  
  2.   
  3. ublic class EqualsAndHashCodeExample {  
  4.  private transient int transientVar = 10;  
  5.  private String name;  
  6.  private double score;  
  7.  private Shape shape = new Square(510);  
  8.  private String[] tags;  
  9.  private int id;  
  10.    
  11.  public String getName() {  
  12.    return this.name;  
  13.  }  
  14.    
  15.  @Override public boolean equals(Object o) {  
  16.    if (o == thisreturn true;  
  17.    if (!(o instanceof EqualsAndHashCodeExample)) return false;  
  18.    EqualsAndHashCodeExample other = (EqualsAndHashCodeExample) o;  
  19.    if (!other.canEqual((Object)this)) return false;  
  20.    if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;  
  21.    if (Double.compare(this.score, other.score) != 0return false;  
  22.    if (!Arrays.deepEquals(this.tags, other.tags)) return false;  
  23.    return true;  
  24.  }  
  25.    
  26.  @Override public int hashCode() {  
  27.    final int PRIME = 59;  
  28.    int result = 1;  
  29.    final long temp1 = Double.doubleToLongBits(this.score);  
  30.    result = (result*PRIME) + (this.name == null ? 43 : this.name.hashCode());  
  31.    result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));  
  32.    result = (result*PRIME) + Arrays.deepHashCode(this.tags);  
  33.    return result;  
  34.  }  
  35.    
  36.  protected boolean canEqual(Object other) {  
  37.    return other instanceof EqualsAndHashCodeExample;  
  38.  }  
  39.    
  40.  public static class Square extends Shape {  
  41.    private final int width, height;  
  42.      
  43.    public Square(int width, int height) {  
  44.      this.width = width;  
  45.      this.height = height;  
  46.    }  
  47.      
  48.    @Override public boolean equals(Object o) {  
  49.      if (o == thisreturn true;  
  50.      if (!(o instanceof Square)) return false;  
  51.      Square other = (Square) o;  
  52.      if (!other.canEqual((Object)this)) return false;  
  53.      if (!super.equals(o)) return false;  
  54.      if (this.width != other.width) return false;  
  55.      if (this.height != other.height) return false;  
  56.      return true;  
  57.    }  
  58.      
  59.    @Override public int hashCode() {  
  60.      final int PRIME = 59;  
  61.      int result = 1;  
  62.      result = (result*PRIME) + super.hashCode();  
  63.      result = (result*PRIME) + this.width;  
  64.      result = (result*PRIME) + this.height;  
  65.      return result;  
  66.    }  
  67.      
  68.    protected boolean canEqual(Object other) {  
  69.      return other instanceof Square;  
  70.    }  
  71.  }  

擴充套件配置:

lombok.config增加:

lombok.equalsAndHashCode.doNotUseGetters = [true | false] (default: false)如果設定為true,lombok將直接訪問欄位,而不是在生成equals和hashcode方法時使用getter(如果可用)。
可以在該註解上配置屬性donotusegetter來標示不使用getter的欄位,這樣可以覆蓋預設配置。
lombok.equalsAndHashCode.callSuper = [call | skip | warn] (default: warn)如果設定為call,lombok將生成對hashCode的超類實現的呼叫。如果設定為skip,則不會生成這樣的呼叫。預設行為warn類似於skip,並帶有附加警告。



7.@NoArgsConstructor, @RequiredArgsConstructor and @AllArgsConstructor

給類增加無參構造器 指定引數的構造器 包含所有引數的構造器

[java] view plain copy
  1.  import lombok.AccessLevel;  
  2. import lombok.RequiredArgsConstructor;  
  3. import lombok.AllArgsConstructor;  
  4. import lombok.NonNull;  
  5.   
  6. @RequiredArgsConstructor(staticName = "of")  
  7. @AllArgsConstructor(access = AccessLevel.PROTECTED)  
  8. public class ConstructorExample<T> {  
  9.   private int x, y;  
  10.   @NonNull private T description;  
  11.     
  12.   @NoArgsConstructor  
  13.   public static class NoArgsExample {  
  14.     @NonNull private String field;  
  15.   }  
  16. }  
翻譯後

[java] view plain copy
  1.  public class ConstructorExample<T> {  
  2.   private int x, y;  
  3.   @NonNull private T description;  
  4.     
  5.   private ConstructorExample(T description) {  
  6.     if (description == nullthrow new NullPointerException("description");  
  7.     this.description = description;  
  8.   }  
  9.     
  10.   public static <T> ConstructorExample<T> of(T description) {  
  11.     return new ConstructorExample<T>(description);  
  12.   }  
  13.     
  14.   @java.beans.ConstructorProperties({"x""y""description"})  
  15.   protected ConstructorExample(int x, int y, T description) {  
  16.     if (description == nullthrow new NullPointerException("description");  
  17.     this.x = x;  
  18.     this.y = y;  
  19.     this.description = description;  
  20.   }  
  21.     
  22.   public static class NoArgsExample {  
  23.     @NonNull private String field;  
  24.       
  25.     public NoArgsExample() {  
  26.     }  
  27.   }  
  28. }  
擴充套件配置:

lombok.anyConstructor.suppressConstructorProperties = [true | false] (default: false)如果將其設定為true,那麼lombok將跳過新增一個@java.bean.ConstructorProperties生成的構造器。這在android和GWT開發中很有用,因為這些註釋通常不可用。

8.@Data

包含以下註解的集合

@ToString,@EqualsAndHashCode,所有欄位的 @Getter 所有非final欄位的@Setter ,@RequiredArgsConstructor

[java] view plain copy
  1.  import lombok.AccessLevel;  
  2. import lombok.Setter;  
  3. import lombok.Data;  
  4. import lombok.ToString;  
  5.   
  6. @Data public class DataExample {  
  7.   private final String name;  
  8.   @Setter(AccessLevel.PACKAGE) private int age;  
  9.   private double score;  
  10.   private String[] tags;  
  11.     
  12.   @ToString(includeFieldNames=true)  
  13.   @Data(staticConstructor="of")  
  14.   public static class Exercise<T> {  
  15.     private final String name;  
  16.     private final T value;  
  17.   }  
  18. }  

翻譯後
[java] view plain copy
  1.  import java.util.Arrays;  
  2.   
  3. public class DataExample {  
  4.   private final String name;  
  5.   private int age;  
  6.   private double score;  
  7.   private String[] tags;  
  8.     
  9.   public DataExample(String name) {  
  10.     this.name = name;  
  11.   }  
  12.     
  13.   public String getName() {  
  14.     return this.name;  
  15.   }  
  16.     
  17.   void setAge(int age) {  
  18.     this.age = age;  
  19.   }  
  20.     
  21.   public int getAge() {  
  22.     return this.age;  
  23.   }  
  24.     
  25.   public void setScore(double score) {  
  26.     this.score = score;  
  27.   }  
  28.     
  29.   public double getScore() {  
  30.     return this.score;  
  31.   }  
  32.     
  33.   public String[] getTags() {  
  34.     return this.tags;  
  35.   }  
  36.     
  37.   public void setTags(String[] tags) {  
  38.     this.tags = tags;  
  39.   }  
  40.     
  41.   @Override public String toString() {  
  42.     return "DataExample(" + this.getName() + ", " + this.getAge() + ", " + this.getScore() + ", " + Arrays.deepToString(this.getTags()) + ")";  
  43.   }  
  44.     
  45.   protected boolean canEqual(Object other) {  
  46.     return other instanceof DataExample;  
  47.   }  
  48.     
  49.   @Override public boolean equals(Object o) {  
  50.     if (o == thisreturn true;  
  51.     if (!(o instanceof DataExample)) return false;  
  52.     DataExample other = (DataExample) o;  
  53.     if (!other.canEqual((Object)this)) return false;  
  54.     if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;  
  55.     if (this.getAge() != other.getAge()) return false;  
  56.     if (Double.compare(this.getScore(), other.getScore()) != 0return false;  
  57.     if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false;  
  58.     return true;  
  59.   }  
  60.     
  61.   @Override public int hashCode() {  
  62.     final int PRIME = 59;  
  63.     int result = 1;  
  64.     final long temp1 = Double.doubleToLongBits(this.getScore());  
  65.     result = (result*PRIME) + (this.getName() == null ? 43 : this.getName().hashCode());  
  66.     result = (result*PRIME) + this.getAge();  
  67.     result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));  
  68.     result = (result*PRIME) + Arrays.deepHashCode(this.getTags());  
  69.     return result;  
  70.   }  
  71.     
  72.   public static class Exercise<T> {  
  73.     private final String name;  
  74.     private final T value;  
  75.       
  76.     private Exercise(String name, T value) {  
  77.       this.name = name;  
  78.       this.value = value;  
  79.     }  
  80.       
  81.     public static <T> Exercise<T> of(String name, T value) {  
  82.       return new Exercise<T>(name, value);  
  83.     }  
  84.       
  85.     public String getName() {  
  86.       return this.name;  
  87.     }  
  88.       
  89.     public T getValue() {  
  90.       return this.value;  
  91.     }  
  92.       
  93.     @Override public String toString() {  
  94.       return "Exercise(name=" + this.getName() + ", value=" + this.getValue() + ")";  
  95.     }  
  96.       
  97.     protected boolean canEqual(Object other) {  
  98.       return other instanceof Exercise;  
  99.     }  
  100.       
  101.     @Override public boolean equals(Object o) {  
  102.       if (o == thisreturn true;  
  103.       if (!(o instanceof Exercise)) return false;  
  104.       Exercise<?> other = (Exercise<?>) o;  
  105.       if (!other.canEqual((Object)this)) return false;  
  106.       if (this.getName() == null ? other.getValue() != null : !this.getName().equals(other.getName())) return false;  
  107.       if (this.getValue() == null ? other.getValue() != null : !this.getValue().equals(other.getValue())) return false;  
  108.       return true;  
  109.     }  
  110.       
  111.     @Override public int hashCode() {  
  112.       final int PRIME = 59;  
  113.       int result = 1;  
  114.       result = (result*PRIME) + (this.getName() == null ? 43 : this.getName().hashCode());  
  115.       result = (result*PRIME) + (this.getValue() == null ? 43 : this.getValue().hashCode());  
  116.       return result;  
  117.     }  
  118.   }  
  119. }  


9.@Value

@value是@data的不可變物件 (不可變物件的用處和建立:https://my.oschina.net/jasonultimate/blog/166810

所有欄位都是私有的,預設情況下是final的,並且不會生成setter。預設情況下,類本身也是final的,因為不可變性不能強制轉化為子類。與@data一樣,有用toString()、equals()和hashCode()方法也是生成的,每個欄位都有一個getter方法,並且一個覆蓋每個引數的構造器也會生成。


10.@Builder

建築者模式

是現在比較推崇的一種構建值物件的方式。

[java] view plain copy
  1.  import lombok.Builder;  
  2. import lombok.Singular;  
  3. import java.util.Set;  
  4.   
  5. @Builder  
  6. public class BuilderExample {  
  7.   private String name;  
  8.   private int age;  
  9.   @Singular private Set<String> occupations;  
  10. }  
翻譯後
[java] view plain copy
  1.  import java.util.Set;  
  2.   
  3. public class BuilderExample {  
  4.   private String name;  
  5.   private int age;  
  6.   private Set<String> occupations;  
  7.     
  8.   BuilderExample(String name, int age, Set<String> occupations) {  
  9.     this.name = name;  
  10.     this.age = age;  
  11.     this.occupations = occupations;  
  12.   }  
  13.     
  14.   public static BuilderExampleBuilder builder() {  
  15.     return new BuilderExampleBuilder();  
  16.   }  
  17.     
  18.   public static class BuilderExampleBuilder {  
  19.     private String name;  
  20.     private int age;  
  21.     private java.util.ArrayList<String> occupations;  
  22.       
  23.     BuilderExampleBuilder() {  
  24.     }  
  25.       
  26.     public BuilderExampleBuilder name(String name) {  
  27.       this.name = name;  
  28.       return this;  
  29.     }  
  30.       
  31.     public BuilderExampleBuilder age(int age) {  
  32.       this.age = age;  
  33.       return this;  
  34.     }  
  35.       
  36.     public BuilderExampleBuilder occupation(String occupation) {  
  37.       if (this.occupations == null) {  
  38.         this.occupations = new java.util.ArrayList<String>();  
  39.       }  
  40.         
  41.       this.occupations.add(occupation);  
  42.       return this;  
  43.     }  
  44.       
  45.     public BuilderExampleBuilder occupations(Collection<? extends String> occupations) {  
  46.       if (this.occupations == null) {  
  47.         this.occupations = new java.util.ArrayList<String>();  
  48.       }  
  49.   
  50.       this.occupations.addAll(occupations);  
  51.       return this;  
  52.     }  
  53.       
  54.     public BuilderExampleBuilder clearOccupations() {  
  55.       if (this.occupations != null) {  
  56.         this.occupations.clear();  
  57.       }  
  58.         
  59.       return this;  
  60.     }  
  61.   
  62.     public BuilderExample build() {  
  63.       // complicated switch statement to produce a compact properly sized immutable set omitted.  
  64.       // go to https://projectlombok.org/features/Singular-snippet.html to see it.  
  65.       Set<String> occupations = ...;  
  66.       return new BuilderExample(name, age, occupations);  
  67.     }  
  68.       
  69.     @java.lang.Override  
  70.     public String toString() {  
  71.       return "BuilderExample.BuilderExampleBuilder(name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")";  
  72.     }  
  73.   }  
  74. }  

11.@SneakyThrows

把checked異常轉化為unchecked異常,好處是不用再往上層方法丟擲了,美其名曰暗埋異常

[java] view plain copy
  1.  import lombok.SneakyThrows;  
  2.   
  3. public class SneakyThrowsExample implements Runnable {  
  4.   @SneakyThrows(UnsupportedEncodingException.class)  
  5.   public String utf8ToString(byte[] bytes) {  
  6.     return new String(bytes, "UTF-8");  
  7.   }  
  8.     
  9.   @SneakyThrows  
  10.   public void run() {  
  11.     throw new Throwable();  
  12.   }  
  13. }  
翻譯後:
[java] view plain copy
  1.  import lombok.Lombok;  
  2.   
  3. public class SneakyThrowsExample implements Runnable {  
  4.   public String utf8ToString(byte[] bytes) {  
  5.     try {  
  6.       return new String(bytes, "UTF-8");  
  7.     } catch (UnsupportedEncodingException e) {  
  8.       throw Lombok.sneakyThrow(e);  
  9.     }  
  10.   }  
  11.     
  12.   public void run() {  
  13.     try {  
  14.       throw new Throwable();  
  15.     } catch (Throwable t) {  
  16.       throw Lombok.sneakyThrow(t);  
  17.     }  
  18.   }  
  19. }  


12.@Synchronized

類似於Synchronized 關鍵字 但是可以隱藏同步鎖

[java] view plain copy
  1. import lombok.Synchronized;  
  2.   
  3. ublic class SynchronizedExample {  
  4.  private final Object readLock = new Object();  
  5.    
  6.  @Synchronized  
  7.  public static void hello() {  
  8.    System.out.println("world");  
  9.  }  
  10.    
  11.  @Synchronized  
  12.  public int answerToLife() {  
  13.    return 42;  
  14.  }  
  15.    
  16.  @Synchronized("readLock")  
  17.  public void foo() {  
  18.    System.out.println("bar");  
  19.  }  
翻譯後
[java] view plain copy
  1. public class SynchronizedExample {  
  2.   private static final Object $LOCK = new Object[0];  
  3.   private final Object $lock = new Object[0];  
  4.   private final Object readLock = new Object();  
  5.     
  6.   public static void hello() {  
  7.     synchronized($LOCK) {  
  8.       System.out.println("world");  
  9.     }  
  10.   }  
  11.     
  12.   public int answerToLife() {  
  13.     synchronized($lock) {  
  14.       return 42;  
  15.     }  
  16.   }  
  17.     
  18.   public void foo() {  
  19.     synchronized(readLock) {  
  20.       System.out.println("bar");  
  21.     }  
  22.   }  
  23. }  

xianzjdk推薦使用Lock了,這個僅供參考


13.@Getter(lazy=true)

如果getter方法計算值需要大量CPU,或者值佔用大量記憶體,第一次呼叫這個getter,它將一次計算一個值,然後從那時開始快取它

[java] view plain copy
  1. import lombok.Getter;  
  2.   
  3. public class GetterLazyExample {  
  4.   @Getter(lazy=trueprivate final double[] cached = expensive();  
  5.     
  6.   private double[] expensive() {  
  7.     double[] result = new double[1000000];  
  8.     for (int i = 0; i < result.length; i++) {  
  9.       result[i] = Math.asin(i);  
  10.     }  
  11.     return result;  
  12.   }  
  13. }  
翻譯後
[java] view plain copy
  1. public class GetterLazyExample {  
  2.  private final java.util.concurrent.AtomicReference<java.lang.Object> cached = new java.util.concurrent.AtomicReference<java.lang.Object>();  
  3.    
  4.  public double[] getCached() {  
  5.    java.lang.Object value = this.cached.get();  
  6.    if (value == null) {  
  7.      synchronized(this.cached) {  
  8.        value = this.cached.get();  
  9.        if (value == null) {  
  10.          final double[] actualValue = expensive();  
  11.          value = actualValue == null ? this.cached : actualValue;  
  12.          this.cached.set(value);  
  13.        }  
  14.      }  
  15.    }  
  16.    return (double[])(value == this.cached ? null : value);  
  17.  }  
  18.    
  19.  private double[] expensive() {  
  20.    double[] result = new double[1000000];  
  21.    for (int i = 0; i < result.length; i++) {  
  22.      result[i] = Math.asin(i);  
  23.    }  
  24.    return result;  
  25.  }  


14.@Log

可以生成各種log物件,方便多了

[java] view plain copy
  1.  import lombok.extern.java.Log;  
  2. import lombok.extern.slf4j.Slf4j;  
  3.   
  4. @Log  
  5. public class LogExample {  
  6.     
  7.   public static void main(String... args) {  
  8.     log.error("Something's wrong here");  
  9.   }  
  10. }  
  11.   
  12. @Slf4j  
  13. public class LogExampleOther {  
  14.     
  15.   public static void main(String... args) {  
  16.     log.error("Something else is wrong here");  
  17.   }  
  18. }  
  19.   
  20. @CommonsLog(topic="CounterLog")  
  21. public class LogExampleCategory {  
  22.   
  23.   public static void main(String... args) {  
  24.     log.error("Calling the 'CounterLog' with a message");  
  25.   }  
  26. }  
翻譯為
[java] view plain copy
  1.  public class LogExample {  
  2.   private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());  
  3.     
  4.   public static void main(String... args) {  
  5.     log.error("Something's wrong here");  
  6.   }  
  7. }  
  8.   
  9. public class LogExampleOther {  
  10.   private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExampleOther.class);  
  11.     
  12.   public static void main(String... args) {  
  13.     log.error("Something else is wrong here");  
  14.   }  
  15. }  
  16.   
  17. public class LogExampleCategory {  
  18.   private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog("CounterLog");  
  19.   
  20.   public static void main(String... args) {  
  21.     log.error("Calling the 'CounterLog' with a message");  
  22.   }  
  23. }  

所有支援的log型別:

@CommonsLogCreatesprivate static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);@JBossLogCreatesprivate static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);@LogCreatesprivate static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());@Log4jCreatesprivate static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);@Log4j2Createsprivate static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);@Slf4j Creates private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);@XSlf4jCreatesprivate static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);

擴充套件配置:

lombok.log.fieldName = an identifier (default: log).生成log欄位的名稱 預設為log lombok.log.fieldIsStatic = [true | false] (default: true)生成log是否是static的 預設為static




官方文件說明:https://projectlombok.org/features/all

Lombok原理

lombok通過簡單的註解標誌就能夠實現複雜的程式碼生成,他是怎麼做到的?

lombok註解不是我們常見的runtime註解,而是source註解或者class註解,
在沒有jsr之前我們可以通過反射在執行是獲取註解值,但是這樣效率很低,而且沒辦法做到編譯檢查,對開發人員一些不合的編碼錯誤給出警告,


JSR 269: Pluggable Annotation Processing API (https://www.jcp.org/en/jsr/detail?id=269) 出現後,我們可以在javac的編譯器利用註解來完成對class檔案的修改。

lombok本質上就是這樣的一個實現了"JSR 269 API"的程式。在使用javac的過程中,它產生作用的具體流程如下:
1)javac對原始碼進行分析,生成一棵抽象語法樹(AST)
2)執行過程中呼叫實現了"JSR 269 API"的lombok程式
3)此時lombok就對第一步驟得到的AST進行處理,找到@Data註解所在類對應的語法樹(AST),然後修改該語法樹(AST),增加getter和setter方法定義的相應樹節點
4)javac使用修改後的抽象語法樹(AST)生成位元組碼檔案,即給class增加新的節點(程式碼塊)

ide中使用Lombok的注意事項


1.專案中要使用lombok 不僅ide要支援(否則一堆錯誤),專案中也要引入jar包

2.如果配置lombok.config檔案,修改檔案的屬性值後,並不會自動重新編譯class檔案,ide編輯器也不會自動更新,所有每次修改配置檔案後最後關閉java檔案視窗重新開啟,並且clean下專案

相關文章