Java開發利器之Lombok

感覺一下Lombok的神奇

Lombok提供了簡單的註解形式, 依賴編譯時代碼生成技術, 幫助咱們簡化代碼, 自動生成基於模板的Java代碼.
看一個具體的例子.html

@Data註解, 會自動生成getter/setter方法, 以及重寫equals(), hashcode()和toString()方法.java

使用Lombok的代碼apache

import lombok.Data;

@Data 
public class DataExample {
  private final String name; //final修飾的類型會自動加到生成的構造方法中
  private double score;
  private String[] tags;
}

等價的原生Java代碼eclipse

public class DataExample {
  private final String name;
  private double score;
  private String[] tags;
  
  public DataExample(String name) {
    this.name = name;
  }
  
  public String getName() {
    return this.name;
  }
  
  public void setScore(double score) {
    this.score = score;
  }
  
  public double getScore() {
    return this.score;
  }
  
  public String[] getTags() {
    return this.tags;
  }
  
  public void setTags(String[] tags) {
    this.tags = tags;
  }
  
  @Override public String toString() {
    return "DataExample(" + this.getName() + ", " + this.getScore() + ", " + Arrays.deepToString(this.getTags()) + ")";
  }
  
  protected boolean canEqual(Object other) {
    return other instanceof DataExample;
  }
  
  @Override public boolean equals(Object o) {
    if (o == this) return true;
    if (!(o instanceof DataExample)) return false;
    DataExample other = (DataExample) o;
    if (!other.canEqual((Object)this)) return false;
    if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
    if (Double.compare(this.getScore(), other.getScore()) != 0) return false;
    if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false;
    return true;
  }
  
  @Override public int hashCode() {
    final int PRIME = 59;
    int result = 1;
    final long temp1 = Double.doubleToLongBits(this.getScore());
    result = (result*PRIME) + (this.getName() == null ? 0 : this.getName().hashCode());
    result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));
    result = (result*PRIME) + Arrays.deepHashCode(this.getTags());
    return result;
  }
}

Lombok使用詳解

@NonNull

給方法參數增長這個註解會自動在方法內對該參數進行是否爲空的校驗,若是爲空,則拋出NullPointerException
使用Lombok的代碼ide

import lombok.NonNull;

public class NonNullExample {
    private String name;
    public NonNullExample(@NonNull Person person) {
        this.name = person.getName();
    }
}

等價的原生Java代碼ui

public class NonNullExample {
    private String name;
    public NonNullExample(Person person) {
        if (person == null) {
            throw new NullPointerException("person");
        }
        this.name = person.getName();
    }
}
@Cleanup

自動管理資源,用在局部變量以前,在當前變量範圍內即將執行完畢退出以前會自動清理資源,自動生成try-finally這樣的代碼來關閉流
使用Lombok的代碼this

import lombok.Cleanup;
import java.io.*;

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);
        }
    }
}

等價的原生Java代碼atom

import java.io.*;

public class CleanupExample {
    public static void main(String[] args) throws IOException {
        InputStream in = new FileInputStream(args[0]);
        try {
            OutputStream out = new FileOutputStream(args[1]);
            try {
                byte[] b = new byte[10000];
                while (true) {
                    int r = in.read(b);
                    if (r == -1) break;
                    out.write(b, 0, r);
                }
            } finally {
                if (out != null) {
                    out.close();
                }
            }
        } finally {
            if (in != null) {
                in.close();
            }
        }
    }
}
@Getter/@Setter

自動生成setter和getter方法了,還能夠指定訪問範圍
使用Lombok的代碼spa

import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;

public class GetterSetterExample {
    @Getter @Setter private int age = 10;
    @Setter(AccessLevel.PROTECTED) private String name;
}

等價的原生Java代碼插件

public class GetterSetterExample {
    private int age = 10;
    private String name;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    protected void setName(String name) {
        this.name = name;
    }
}
@ToString

用在類上,能夠自動覆寫toString方法,固然還能夠加其餘參數,例如@ToString(exclude=」id」)排除id屬性,或者@ToString(callSuper=true, includeFieldNames=true)調用父類的toString方法,包含全部屬性
使用Lombok的代碼

import lombok.ToString; 
@ToString(exclude="id")
public class ToStringExample {
   private static final int STATIC_VAR = 10;
   private String name;
   private String[] tags;
   private int id;
   
   public String getName() {
     return this.getName();
   }  
}

等價的原生Java代碼

public class ToStringExample {
   private static final int STATIC_VAR = 10;
   private String name;
   private String[] tags;
   private int id;
   
   public String getName() {
     return this.getName();
   }

   @Override public String toString() {
     return "ToStringExample(" + this.getName() + ", " + Arrays.deepToString(this.tags) + ")";
   }
}
@EqualsAndHashCode

用在類上,自動生成equals方法和hashCode方法
使用Lombok的代碼

import lombok.EqualsAndHashCode;

@EqualsAndHashCode(exclude={"id"})
public class EqualsAndHashCodeExample {
  private transient int transientVar = 10;
  private String name;
  private double score;
  private String[] tags;
  private int id;
  
  public String getName() {
    return this.name;
  }
}

等價的原生Java代碼

import java.util.Arrays;

public class EqualsAndHashCodeExample {
  private transient int transientVar = 10;
  private String name;
  private double score;
  private String[] tags;
  private int id;
  
  public String getName() {
    return this.name;
  }
  
  @Override public boolean equals(Object o) {
    if (o == this) return true;
    if (!(o instanceof EqualsAndHashCodeExample)) return false;
    EqualsAndHashCodeExample other = (EqualsAndHashCodeExample) o;
    if (!other.canEqual((Object)this)) return false;
    if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
    if (Double.compare(this.score, other.score) != 0) return false;
    if (!Arrays.deepEquals(this.tags, other.tags)) return false;
    return true;
  }
  
  @Override public int hashCode() {
    final int PRIME = 59;
    int result = 1;
    final long temp1 = Double.doubleToLongBits(this.score);
    result = (result*PRIME) + (this.name == null ? 0 : this.name.hashCode());
    result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));
    result = (result*PRIME) + Arrays.deepHashCode(this.tags);
    return result;
  }
  
  protected boolean canEqual(Object other) {
    return other instanceof EqualsAndHashCodeExample;
  }
}
@NoArgsConstructor, @RequiredArgsConstructor 和 @AllArgsConstructor
  • @NoArgsConstructor
    生成一個無參數的構造方法

  • @RequiredArgsConstructor
    會生成一個包含常量,和標識了NotNull的變量 的構造方法。生成的構造方法是private,若是指定staticName = 「of」參數,同時還會生成一個返回類對象的靜態工廠方法

  • @AllArgsConstructor
    會生成一個包含全部變量,同時若是變量使用了NotNull, 會進行是否爲空的校驗

使用Lombok的代碼

@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;
    }
}

等價的原生Java代碼

public class ConstructorExample<t> {
    private int x, y;
    private T description;
    private ConstructorExample(T description) {
        if (description == null) throw new NullPointerException("description");
        this.description = description;
    }

    public static <t> ConstructorExample<t> of(T description) {
        return new ConstructorExample<t>(description);
    }

    protected ConstructorExample(int x, int y, T description) {
        if (description == null) throw new NullPointerException("description");
        this.x = x;
        this.y = y;
        this.description = description;
    }

    public static class NoArgsExample {
        private String field;
        public NoArgsExample() {
        }
    }

}
@Data

註解在類上,至關於同時使用了@ToString、@EqualsAndHashCode、@Getter、@Setter和@RequiredArgsConstrutor這些註解

@Value

用在類上,是@Data的不可變形式,至關於爲屬性添加final聲明,只提供getter方法,而不提供setter方法
使用Lombok的代碼

import lombok.experimental.Value;
 
@Value 
public class ValueExample {
   String name;
   double score;
   protected String[] tags;
}

等價的原生Java代碼

import java.util.Arrays;

public final class ValueExample {
  private final String name;
  private final double score;
  protected final String[] tags;
  
  public ValueExample(String name, double score, String[] tags) {
    this.name = name;
    this.score = score;
    this.tags = tags;
  }
  
  public String getName() {
    return this.name;
  }
   
  public double getScore() {
    return this.score;
  }
  
  public String[] getTags() {
    return this.tags;
  }
  
  @java.lang.Override
  public boolean equals(Object o) {
    if (o == this) return true;
    if (!(o instanceof ValueExample)) return false;
    final ValueExample other = (ValueExample)o;
    final Object this$name = this.getName();
    final Object other$name = other.getName();
    if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false;
    if (Double.compare(this.getScore(), other.getScore()) != 0) return false;
    if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false;
    return true;
  }
  
  @java.lang.Override
  public int hashCode() {
    final int PRIME = 59;
    int result = 1;
    final Object $name = this.getName();
    result = result * PRIME + ($name == null ? 43 : $name.hashCode());
    final long $score = Double.doubleToLongBits(this.getScore());
    result = result * PRIME + (int)($score >>> 32 ^ $score);
    result = result * PRIME + Arrays.deepHashCode(this.getTags());
    return result;
  }
  
  @java.lang.Override
  public String toString() {
    return "ValueExample(name=" + getName() + ", score=" + getScore() + ", tags=" + Arrays.deepToString(getTags()) + ")";
  }
}
@Builder

用在類、構造器、方法上,爲你提供複雜的builder APIs,讓你能夠像以下方式同樣調用Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build()
使用Lombok的代碼

import lombok.experimental.Builder;
import java.util.Set;

@Builder
public class BuilderExample {
    private String name;
    private int age;
    private Set<string> occupations;

    public static void main(String args[]) {
        BuilderExample builderExample = BuilderExample.builder().build();
    }
}

等價的原生Java代碼

import java.util.Set;

public class BuilderExample {
    private String name;
    private int age;
    private Set<string> occupations;

    BuilderExample(String name, int age, Set<string> occupations) {
        this.name = name;
        this.age = age;
        this.occupations = occupations;
}

    public static BuilderExampleBuilder builder() {
        return new BuilderExampleBuilder();
    }

    

    public static class BuilderExampleBuilder {
        private String name;
        private int age;
        private java.util.ArrayList<string> occupations;

        BuilderExampleBuilder() {}

        public BuilderExampleBuilder name(String name) {
            this.name = name;
            return this;
        }

        public BuilderExampleBuilder age(int age) {
            this.age = age;
            return this;
        }

        public BuilderExampleBuilder occupation(String occupation) {
            if (this.occupations == null) {
                this.occupations = new java.util.ArrayList<string>();
            }
            this.occupations.add(occupation);
            return this;
        }

        public BuilderExampleBuilder occupations(Collection<? extends String> occupations) {
            if (this.occupations == null) {
                this.occupations = new java.util.ArrayList<string>();
            }
            this.occupations.addAll(occupations);
            return this;
        }

        public BuilderExampleBuilder clearOccupations() {
            if (this.occupations != null) {
                this.occupations.clear();
            }
            return this;
        }

        public BuilderExample build() {
            // complicated switch statement to produce a compact properly sized immutable set omitted.
            // go to https://projectlombok.org/features/Singular-snippet.html to see it.
            Set<string> occupations = ...;
            return new BuilderExample(name, age, occupations);
        }

        @java.lang.Override
        public String toString() {
            return "BuilderExample.BuilderExampleBuilder(name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")";
        }
    }
}
@SneakyThrows

自動拋受檢異常,而無需顯式在方法上使用throws語句
使用Lombok的代碼

import lombok.SneakyThrows;

public class SneakyThrowsExample implements Runnable {
    @SneakyThrows(UnsupportedEncodingException.class)
    public String utf8ToString(byte[] bytes) {
        return new String(bytes, "UTF-8");
    }

    @SneakyThrows
    public void run() {
        throw new Throwable();
    }
}

等價的原生Java代碼

import lombok.Lombok;

public class SneakyThrowsExample implements Runnable {
    public String utf8ToString(byte[] bytes) {
        try {
            return new String(bytes, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw Lombok.sneakyThrow(e);
        }
    }

    public void run() {
        try {
            throw new Throwable();
        } catch (Throwable t) {
            throw Lombok.sneakyThrow(t);
        }
    }
}
@Synchronized

用在方法上,將方法聲明爲同步的,並自動加鎖,而鎖對象是一個私有的屬性$lock或$LOCK,而java中的synchronized關鍵字鎖對象是this,鎖在this或者本身的類對象上存在反作用,就是你不能阻止非受控代碼去鎖this或者類對象,這可能會致使競爭條件或者其它線程錯誤
使用Lombok的代碼

import lombok.Synchronized;

public class SynchronizedExample {
    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");
    }
}

等價的原生Java代碼

public class SynchronizedExample {
    private static final Object $LOCK = new Object[0];
    private final Object $lock = new Object[0];
    private final Object readLock = new Object();

    public static void hello() {
        synchronized($LOCK) {
            System.out.println("world");
        }
    }

    public int answerToLife() {
        synchronized($lock) {
            return 42;
        }
    }

    public void foo() {
        synchronized(readLock) {
            System.out.println("bar");
        }
    }
}
@Getter(lazy=true)

能夠替代經典的Double Check Lock樣板代碼
使用Lombok的代碼

public class GetterLazyExample {
    @Getter(lazy = true)
    private final double[] cached = expensive();
    private double[] expensive() {
        double[] result = new double[1000000];
        for (int i = 0; i < result.length; i++) {
            result[i] = Math.asin(i);
        }
        return result;
    }
}

等價的原生Java代碼

import java.util.concurrent.atomic.AtomicReference;
public class GetterLazyExample {
    private final AtomicReference<java.lang.Object> cached = new AtomicReference<>();
    public double[] getCached() {
        java.lang.Object value = this.cached.get();
        if (value == null) {
            synchronized (this.cached) {
                value = this.cached.get();
                if (value == null) {
                    final double[] actualValue = expensive();
                    value = actualValue == null ? this.cached : actualValue;
                    this.cached.set(value);
                }
            }
        }
        return (double[]) (value == this.cached ? null : value);
    }
    private double[] expensive() {
        double[] result = new double[1000000];
        for (int i = 0; i < result.length; i++) {
            result[i] = Math.asin(i);
        }
        return result;
    }
}
@Log

根據不一樣的註解生成不一樣類型的log對象,可是實例名稱都是log,有六種可選實現類

@CommonsLog 
Creates log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);

@Log 
Creates log = java.util.logging.Logger.getLogger(LogExample.class.getName());

@Log4j 
Creates log = org.apache.log4j.Logger.getLogger(LogExample.class);

@Log4j2 
Creates log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);

@Slf4j 
Creates log = org.slf4j.LoggerFactory.getLogger(LogExample.class);

@XSlf4j 
Creates log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);

使用Lombok的代碼

import lombok.extern.java.Log;
 import lombok.extern.slf4j.Slf4j;
 
 @Log
 public class LogExample {
   public static void main(String... args) {
     log.error("Something's wrong here");
   }
 }
 
 @Slf4j
 public class LogExampleOther {
   public static void main(String... args) {
     log.error("Something else is wrong here");
   }
 }
 
 @CommonsLog(topic="CounterLog")
 public class LogExampleCategory {
   public static void main(String... args) {
     log.error("Calling the 'CounterLog' with a message");
   }
 }

等價的原生Java代碼

public class LogExample {
  private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
  
  public static void main(String... args) {
    log.error("Something's wrong here");
  }
}

public class LogExampleOther {
  private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExampleOther.class);
  
  public static void main(String... args) {
    log.error("Something else is wrong here");
  }
}

public class LogExampleCategory {
  private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog("CounterLog");

  public static void main(String... args) {
    log.error("Calling the 'CounterLog' with a message");
  }
}

Lombok安裝

  • jar包依賴
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.8</version>
</dependency>
  • 安裝IDE插件
    • IntelliJ
      經過IntelliJ的插件中心安裝Lombok插件
    • Eclipse
      1. 下載Jar包,下載地址:http://projectlombok.org/download.html
      2. 將lombok.jar複製到myeclipse.ini/eclipse.ini所在的文件夾目錄下
      3. 打開eclipse.ini/myeclipse.ini,在最後面插入如下兩行並保存:
        -Xbootclasspath/a:lombok.jar
        -javaagent:lombok.jar
      4. 重啓eclipse/myeclipse

Lombok官網地址:https://projectlombok.org/

相關文章
相關標籤/搜索