前提
這篇文章主要介紹lombok的使用,至於lombok的源碼和原理暫不探究,可以看上一篇文章插件化注解處理API去了解lombok的基本原理。參考資料:
簡介
Project Lombok是一個java庫,它可以自動插入到編輯器中,並構建工具,使java更加豐富。再也不用getter或equals方法了。盡早訪問未來的java特性,比如val等等。這個就是lombok的官方簡介(例如Jdk9中新增的val關鍵字在lombok中很早就出現了)。lombok實際上是基於JSR-269的插件化注解處理API,在編譯期間對使用了特定注解的類、方法、屬性或者代碼片段進行動態修改,添加或者實現其自定義功能的類庫。
安裝
maven依賴
在項目中使用到lombok的注解必須引入其依賴:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${version}</version>
</dependency>
當前的最新版本為:1.16.20。
插件
如果不為IDE安裝lombok的插件,IDE無法識別lombok編譯期動態生成的代碼,表現為代碼塊標紅,因此需要安裝其插件,插件地址:https://projectlombok.org/download。
下載完成后,將會得到一個jar包lombok-xx.xx.xx.jar,直接使用命令java -jar lombok-xx.xx.xx.jar運行即可,然后按照指引安裝到IDEA、eclipse或者myeclipse。
lombok注解
@val
@val用於聲明修飾符為final的局部變量類型,使用的時候不需要編寫實際的類型,這一點依賴於編譯器的類型推導。@val的作用域是局部變量。舉例如下:
使用lombok:
import java.util.ArrayList;
import java.util.HashMap;
import lombok.val;
public class ValExample {
public String example() {
val example = new ArrayList<String>();
example.add("Hello, World!");
val foo = example.get(0);
return foo.toLowerCase();
}
}
相當於原生Java:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class ValExample {
public String example() {
final ArrayList<String> example = new ArrayList<String>();
example.add("Hello, World!");
final String foo = example.get(0);
return foo.toLowerCase();
}
}
@var
@var的功能類似於@val,不過@var修飾的是非final修飾的局部變量。
@NonNull
@NonNull的作用域是屬性(field)、方法參數或、構造函數參數以及局部變量(LOCAL_VARIABLE),為這些參數添加一個空檢查語句,基本格式是:if(param == null) {throw new NullPointerException("param ");}
。
使用lombok:
import lombok.NonNull;
public class NonNullExample extends Something {
private String name;
public NonNullExample(@NonNull Person person) {
super("Hello");
this.name = person.getName();
}
}
相當於原生Java:
import lombok.NonNull;
public class NonNullExample extends Something {
private String name;
public NonNullExample(@NonNull Person person) {
super("Hello");
if (person == null) {
throw new NullPointerException("person");
}
this.name = person.getName();
}
}
@Cleanup
你可以使用@Cleanup來確保在代碼執行路徑退出當前范圍之前自動清理給定的資源,一般使用在流的局部變量的關閉。可以通過value()指定關閉資源的方法名,注意,關閉資源的方法必須是無參void方法,默認的關閉資源方法名稱是"close"。
使用lombok:
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:
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
@Getter/@Setter作用域是屬性或者類。@Getter為指定屬性或者類中的所有屬性生成Getter方法,@Setter指定非final屬性或者類中的所有非final屬性生成Setter方法。可以通過@Getter/@Setter的value()中的AccessLevel屬性來指定生成的方法的修飾符,可以通過@Getter的布爾值屬性lazy來指定是否延遲加載。
使用lombok:
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
public class GetterSetterExample {
/**
* Age of the person. Water is wet.
*
* @param age New value for this person's age. Sky is blue.
* @return The current value of this person's age. Circles are round.
*/
@Getter @Setter private int age = 10;
/**
* Name of the person.
* -- SETTER --
* Changes the name of this person.
*
* @param name The new value.
*/
@Setter(AccessLevel.PROTECTED) private String name;
@Override public String toString() {
return String.format("%s (age: %d)", name, age);
}
}
相當於原生Java:
public class GetterSetterExample {
/**
* Age of the person. Water is wet.
*/
private int age = 10;
/**
* Name of the person.
*/
private String name;
@Override public String toString() {
return String.format("%s (age: %d)", name, age);
}
/**
* Age of the person. Water is wet.
*
* @return The current value of this person's age. Circles are round.
*/
public int getAge() {
return age;
}
/**
* Age of the person. Water is wet.
*
* @param age New value for this person's age. Sky is blue.
*/
public void setAge(int age) {
this.age = age;
}
/**
* Changes the name of this person.
*
* @param name The new value.
*/
protected void setName(String name) {
this.name = name;
}
}
@ToString
@ToString的作用域是類,主要作用是覆蓋類中的toString方法。@ToString的屬性比較多,簡介如下:
- includeFieldNames():布爾值,默認為true,true表示拼接toString的時候使用屬性名。
- exclude():字符串數組,默認為空,用於通過屬性名排除拼接toString時使用的屬性。
- of():exclude()屬性的對立屬性,意思就是include。
- callSuper():布爾值,默認為false,是否調用父類的屬性。
- doNotUseGetters():布爾值,默認為false,true表示拼接toString的時候使用屬性值而不是其Getter方法。
下面是官方例子:
使用lombok:
import lombok.ToString;
@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.name;
}
@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;
}
}
}
相當於原生Java:
import java.util.Arrays;
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();
}
public static class Square extends Shape {
private final int width, height;
public Square(int width, int height) {
this.width = width;
this.height = height;
}
@Override public String toString() {
return "Square(super=" + super.toString() + ", width=" + this.width + ", height=" + this.height + ")";
}
}
@Override public String toString() {
return "ToStringExample(" + this.getName() + ", " + this.shape + ", " + Arrays.deepToString(this.tags) + ")";
}
}
@EqualsAndHashCode
@EqualsAndHashCode的作用域是類,用於生成equals()和hashCode()方法。此注解的屬性比較多,不過和@ToString類似。舉例如下:
使用lombok:
import lombok.EqualsAndHashCode;
@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;
}
}
}
相當於原生Java:
import java.util.Arrays;
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;
}
@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 ? 43 : 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;
}
public static class Square extends Shape {
private final int width, height;
public Square(int width, int height) {
this.width = width;
this.height = height;
}
@Override public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Square)) return false;
Square other = (Square) o;
if (!other.canEqual((Object)this)) return false;
if (!super.equals(o)) return false;
if (this.width != other.width) return false;
if (this.height != other.height) return false;
return true;
}
@Override public int hashCode() {
final int PRIME = 59;
int result = 1;
result = (result*PRIME) + super.hashCode();
result = (result*PRIME) + this.width;
result = (result*PRIME) + this.height;
return result;
}
protected boolean canEqual(Object other) {
return other instanceof Square;
}
}
}
@NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor
這三個注解的作用域都是類。@NoArgsConstructor作用是生成一個無參數的構造函數。@AllArgsConstructor作用是生成一個具有所有字段的構造函數。@RequiredArgsConstructor的作用是為每一個使用了final或者@NonNull修飾的屬性都生成一個只有一個參數的構造函數。這三個注解都可以通過staticName()指定構造的命名,通過access()指定構造的修飾符。@NoArgsConstructor的屬性force()默認值為false,當類中存在final屬性的時候使用了@NoArgsConstructor會編譯錯誤,如果force()值為true,那么會把final修飾的屬性作為"無參數構造"的參數,並且把屬性賦值為0、null或者false。
使用lombok:
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.AllArgsConstructor;
import lombok.NonNull;
@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;
@NonNull 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);
}
@java.beans.ConstructorProperties({"x", "y", "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 {
@NonNull private String field;
public NoArgsExample() {
}
}
}
@Data
@Data的作用域是類,相當於同時應用了@Getter、@Setter、@ToString、@EqualsAndHashCode、@RequiredArgsConstructor。如果已經顯示自定義過構造函數,就不會再自動生成構造函數了。舉例如下:
使用lombok:
import lombok.AccessLevel;
import lombok.Setter;
import lombok.Data;
import lombok.ToString;
@Data public class DataExample {
private final String name;
@Setter(AccessLevel.PACKAGE) private int age;
private double score;
private String[] tags;
@ToString(includeFieldNames=true)
@Data(staticConstructor="of")
public static class Exercise<T> {
private final String name;
private final T value;
}
}
相當於原生Java:
import java.util.Arrays;
public class DataExample {
private final String name;
private int age;
private double score;
private String[] tags;
public DataExample(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
void setAge(int age) {
this.age = age;
}
public int getAge() {
return this.age;
}
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.getAge() + ", " + 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 (this.getAge() != other.getAge()) 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 ? 43 : this.getName().hashCode());
result = (result*PRIME) + this.getAge();
result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));
result = (result*PRIME) + Arrays.deepHashCode(this.getTags());
return result;
}
public static class Exercise<T> {
private final String name;
private final T value;
private Exercise(String name, T value) {
this.name = name;
this.value = value;
}
public static <T> Exercise<T> of(String name, T value) {
return new Exercise<T>(name, value);
}
public String getName() {
return this.name;
}
public T getValue() {
return this.value;
}
@Override public String toString() {
return "Exercise(name=" + this.getName() + ", value=" + this.getValue() + ")";
}
protected boolean canEqual(Object other) {
return other instanceof Exercise;
}
@Override public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof Exercise)) return false;
Exercise<?> other = (Exercise<?>) o;
if (!other.canEqual((Object)this)) return false;
if (this.getName() == null ? other.getValue() != null : !this.getName().equals(other.getName())) return false;
if (this.getValue() == null ? other.getValue() != null : !this.getValue().equals(other.getValue())) return false;
return true;
}
@Override public int hashCode() {
final int PRIME = 59;
int result = 1;
result = (result*PRIME) + (this.getName() == null ? 43 : this.getName().hashCode());
result = (result*PRIME) + (this.getValue() == null ? 43 : this.getValue().hashCode());
return result;
}
}
}
@Value
@Value的作用域是類,和@Data類似,但是用於不可變類型。生成的類和所有字段都設置為final,所有字段都為private,自動生成Getter但是沒有Setter,會生成初始化所有字段的構造函數。相當於同時應用了final、 @ToString、 @EqualsAndHashCode、 @AllArgsConstructor 、@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE)和@Getter。
使用lombok:
import lombok.AccessLevel;
import lombok.experimental.NonFinal;
import lombok.experimental.Value;
import lombok.experimental.Wither;
import lombok.ToString;
@Value public class ValueExample {
String name;
@Wither(AccessLevel.PACKAGE) @NonFinal int age;
double score;
protected String[] tags;
@ToString(includeFieldNames=true)
@Value(staticConstructor="of")
public static class Exercise<T> {
String name;
T value;
}
}
相當於原生Java:
import java.util.Arrays;
public final class ValueExample {
private final String name;
private int age;
private final double score;
protected final String[] tags;
@java.beans.ConstructorProperties({"name", "age", "score", "tags"})
public ValueExample(String name, int age, double score, String[] tags) {
this.name = name;
this.age = age;
this.score = score;
this.tags = tags;
}
public String getName() {
return this.name;
}
public int getAge() {
return this.age;
}
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 (this.getAge() != other.getAge()) 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());
result = result * PRIME + this.getAge();
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() + ", age=" + getAge() + ", score=" + getScore() + ", tags=" + Arrays.deepToString(getTags()) + ")";
}
ValueExample withAge(int age) {
return this.age == age ? this : new ValueExample(name, age, score, tags);
}
public static final class Exercise<T> {
private final String name;
private final T value;
private Exercise(String name, T value) {
this.name = name;
this.value = value;
}
public static <T> Exercise<T> of(String name, T value) {
return new Exercise<T>(name, value);
}
public String getName() {
return this.name;
}
public T getValue() {
return this.value;
}
@java.lang.Override
public boolean equals(Object o) {
if (o == this) return true;
if (!(o instanceof ValueExample.Exercise)) return false;
final Exercise<?> other = (Exercise<?>)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;
final Object this$value = this.getValue();
final Object other$value = other.getValue();
if (this$value == null ? other$value != null : !this$value.equals(other$value)) 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 Object $value = this.getValue();
result = result * PRIME + ($value == null ? 43 : $value.hashCode());
return result;
}
@java.lang.Override
public String toString() {
return "ValueExample.Exercise(name=" + getName() + ", value=" + getValue() + ")";
}
}
}
@Builder
@Builder的作用域是類,使用此注解后類中新增一個成員類(Builder)將會使用構建者模式,編譯時增加了一個Builder內部類和全字段的構造器。@Builder.Default用於指定Builder中的屬性的默認值,@Singular用於告訴lombok當前屬性類型是集合類型,lombok會為信任的集合類型添加"adder"方法而不是"setter"方法。
使用lombok:
import lombok.Builder;
import lombok.Singular;
import java.util.Set;
@Builder
public class BuilderExample {
@Builder.Default private long created = System.currentTimeMillis();
private String name;
private int age;
@Singular private Set<String> occupations;
}
相當於原生Java:
import java.util.Set;
public class BuilderExample {
private long created;
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;
}
private static long $default$created() {
return System.currentTimeMillis();
}
public static BuilderExampleBuilder builder() {
return new BuilderExampleBuilder();
}
public static class BuilderExampleBuilder {
private long created;
private boolean created$set;
private String name;
private int age;
private java.util.ArrayList<String> occupations;
BuilderExampleBuilder() {
}
public BuilderExampleBuilder created(long created) {
this.created = created;
this.created$set = true;
return this;
}
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.
Set<String> occupations = ...;
return new BuilderExample(created$set ? created : BuilderExample.$default$created(), name, age, occupations);
}
@java.lang.Override
public String toString() {
return "BuilderExample.BuilderExampleBuilder(created = " + this.created + ", name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")";
}
}
}
@Synchronized
@Synchronized的作用域是方法,用於方法同步,使用此注解后,方法體中的代碼塊自動包含在一個synchronize塊中。synchronize塊加鎖的對象一定是類中的一個成員屬性,可以通過@Synchronized的value()指定,如果不存在則由lombok新建,一般是private final Object $lock = new Object[0];
。
使用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");
}
}
}
@SneakyThrows
@SneakyThrows的作用域是構造或者方法,用於自動捕獲(隱藏)檢查異常。我們知道,java對於檢查異常,需要在編碼時進行捕獲,或者拋出。該注解的作用是將檢查異常包裝為運行時異常,那么編碼時就無需處理異常了。
提示:不過這並不是友好的編碼方式,因為你編寫的api的使用者,不能顯式的獲知需要處理檢查異常。
使用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);
}
}
}
@Log
@Log的作用域是類,用於生成日志API句柄。目前支持的類型如下:
@CommonsLog
相當於在類中定義了:private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class);
@JBossLog
相當於在類中定義了:private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class);
@Log
相當於在類中定義了:private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName());
@Log4j
相當於在類中定義了:private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class);
@Log4j2
相當於在類中定義了:private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class);
@Slf4j
相當於在類中定義了:private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class);
@XSlf4j
相當於在類中定義了:private static final org.slf4j.ext.XLogger 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並不是一個十分奇特的框架,它用到的技術已經是"很老的"Jdk6的一個特性,但是它表現出來的特性確實令人感覺它就是奇技淫巧。畢竟是奇技淫巧,很多不了解的人就會望然生畏,覺得使用了它很可能會導致系統出現無法預知的BUG之類(這里吐槽一下,筆者所在的公司禁用lombok)。其實,基於插件化注解處理API生成代碼是位於編譯期間,如果出現任何問題,很明顯編譯是不可能通過的。如果覺得lombok有問題,大可以去翻看每一個編譯后的文件,看它們有沒有表現異常。lombok在日常編碼中可以極大提高效率,因此它一定是百益而無一害的。
(全文完)
技術公眾號(《Throwable文摘》),不定期推送筆者原創技術文章(絕不抄襲或者轉載):
娛樂公眾號(《天天沙雕》),甄選奇趣沙雕圖文和視頻不定期推送,緩解生活工作壓力: