<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Laziness is a virtue!
每當寫pojo類時,都會重複寫一些setter/getter/toString
方法等大量的模版程式碼,無聊繁瑣卻又不得不做,這會讓這個類變得又臭又長,卻沒有多少實質的東西
Lombok是一個旨在減少程式碼開發工作的Java庫。它提供了一些簡單的註解,並以此來消除java中臃腫的模版程式碼,比如 pojo 中最常見的 setter/getter
方法, 比如 toString
方法, 比如 equals
方法等等,還可以幫助我們關閉流,即使 JDK7 中已經有了 TWR 特性,但這個包很值得一試。
通過幾個簡單的註解,將模版程式碼在編譯時寫入程式。使用 eclipse 可以在 Outline 視窗看到生成的方法,但是在原始碼裡是乾淨的.
首先去 lombok 官網下載jar 包。
只是把 jar 包下載下來並匯入工程中,會發現 IDE 不識別它的註解,那怎麼辦?
將 lombok.jar
複製到 eclipse.ini
所在的目錄下,然後編輯 eclipse.ini
檔案, 在它的末尾插入以下兩行並儲存:
Xbootclasspath/a:lombok.jar javaagent:lombok.jar
接著重啟 eclipse 就可以愉快地使用這個庫了。
在 IntelliJ 的外掛中心可以找到它。
Lombok 提供的註解不多,但都好用,簡要說一下常用的幾個。
這兩個註解修飾成員變數,可用於生成 setter/gettter
模版程式碼。
舉個栗子:
import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; public class Student { @Setter @Getter private String name; @Getter(AccessLevel.PROTECTED) private int age;// 可以指定存取許可權 @Setter @Getter private String[] hobbies; }
將位元組碼檔案反編譯後可以看到下面這段程式碼
public class Student { private String name; private int age; private String[] hobbies; public String getName() { return this.name; } public void setName(String name) { this.name = name; } protected int getAge() { return this.age; } public String[] getHobbies() { return this.hobbies; } public void setHobbies(String[] hobbies) { this.hobbies = hobbies; } }
import lombok.ToString; @ToString(exclude="id") public class ToStringExample { private int id; private String name; private String[] tags; }
編譯後
import java.util.Arrays; public class ToStringExample { public String toString() { return "ToStringExample(name=" + this.name + ", tags=" + Arrays.deepToString(this.tags) + ")"; } private int id; private String name; private String[] tags; }
我們發現,對於陣列,在寫 toString
方法時使用了 Arrays
類的 靜態方法 deepToString
。
來看 eclipse 自動生成的 toString
方法:
@Override public String toString() { return "ToStringExample [name=" + name + ", tags=" + Arrays.toString(tags) + "]"; }
eclipse 中對於陣列採用的是 Arrays.toString()
。
區別:這兩個方法的區別是這樣的,對於多維陣列,使用 toString
只能列印出內部陣列的名字,這時需要使用 deepToString
方法,它能將內部陣列的內容全部列印出來。
可以指定哪些屬性不出現在 toString
方法中, 比如 exclude={"id", "name"}
當類中有成員變數的 getter
方法時,生成 toString
方法會使用這些 getter
方法,比如
public String toString() { return "ToStringExample(name=" + getName() + ", tags=" + Arrays.deepToString(getTags()) + ")"; }
但是將該引數設定為 true
時(預設為 false),生成 toString
方法時就不會使用 getter
方法,而是直接使用這些成員變數,比如
public String toString() { return "ToStringExample(name=" + this.name + ", tags=" + Arrays.deepToString(this.tags) + ")"; }
原本是以 fieldName = fieldValue
的格式來生成 toString
方法的,但是將該引數設定為 false
後(預設是 true),就不會顯示 fieldName
了,而只是生成 fieldValue
, 比如
public String toString() { return "ToStringExample(" + getId() + ", " + getName() + ", " + Arrays.deepToString(getTags()) + ")"; }
若類 A 是類 B 的子類,那麼在 A 類重寫 toString
時,若把該引數設定為 true
,會加入下面這段程式碼,即也會把父類別 B 的 toString
也寫入。
super=" + super.toString()
檢查傳入物件是否為 Null,若為null,則丟擲NullPointerException
異常。
舉個栗子
import lombok.NonNull; public class NonNullExample extends Student{ private String name; public NonNullExample(@NonNull Student student) { this.name = student.getName(); } }
編譯後程式碼
import lombok.NonNull; public class NonNullExample extends Student { private String name; public NonNullExample(@NonNull Student student) { if (student == null) throw new NullPointerException("student"); this.name = student.getName(); } }
用在類上,用於生成 equals
和 hashcode
方法。
舉個栗子
@EqualsAndHashCode(exclude={"id"}) public class EqualsAndHashCodeExample { private transient int transientVar = 10; private String name; private double score; private String[] tags; private int id; }
編譯後程式碼
import java.util.Arrays; public class EqualsAndHashCodeExample { public int hashCode() { int PRIME = 59; int result = 1; Object $name = this.name; result = result * 59 + ($name == null ? 43 : $name.hashCode()); long $score = Double.doubleToLongBits(this.score); result = result * 59 + (int)($score ^ $score >>> 32); result = result * 59 + Arrays.deepHashCode(this.tags); return result; } protected boolean canEqual(Object other) { return other instanceof EqualsAndHashCodeExample; } public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof EqualsAndHashCodeExample)) return false; EqualsAndHashCodeExample other = (EqualsAndHashCodeExample)o; if (!other.canEqual(this)) return false; Object this$name = this.name; Object other$name = other.name; if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false; if (Double.compare(this.score, other.score) != 0) return false; return Arrays.deepEquals(this.tags, other.tags); } private transient int transientVar = 10; private String name; private double score; private String[] tags; private int id; }
可以看出transient
修飾的變數,不會參與。
引數 of
用來指定參與的變數,其他的跟 @ToString
註解類似。
該註解用於修飾類,會自動生成getter/setter
方法, 以及重寫equals()
, hashcode()
和toString()
方法。
該註解可以用來自動管理資源,用在區域性變數之前,在當前變數範圍內即將執行完畢退出之前會自動清理資源, 自動生成tryfinally
這樣的程式碼來關閉流。
舉個栗子:
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); } } }
這三個註解修飾在類上。
@NoArgsConstructor
用於生成一個無參構造方法。
@RequiredArgsConstructor
會生成一個包含了被@NotNull
標識的變數的構造方法。同樣可以設定生成構造方法的許可權,使用 access
引數進行設定。
@AllArgsConstructor
會生成一個包含所有變數, 同時如果變數使用了@NotNull
,會進行是否為空的校驗。
舉個栗子:
import lombok.*; @RequiredArgsConstructor(staticName = "of") @AllArgsConstructor(access = AccessLevel.PROTECTED) public class ConstructorExample { private int x; private int y; @NonNull private String desc; @NoArgsConstructor public class NoArgsExample{ private String field; } }
這與下面這段程式碼是等價的,
import java.beans.ConstructorProperties; public class ConstructorExample { public static ConstructorExample of(@lombok.NonNull String desc) { return new ConstructorExample(desc); } private ConstructorExample(@lombok.NonNull String desc) { if (desc == null) throw new NullPointerException("desc"); this.desc = desc; } @ConstructorProperties({"x", "y", "desc"}) protected ConstructorExample(int x, int y, @lombok.NonNull String desc) { if (desc == null) throw new NullPointerException("desc"); this.x = x; this.y = y; this.desc = desc; } private int x; private int y; @lombok.NonNull private String desc; public class NoArgsExample { private String field; public NoArgsExample() {} } }
該註解用於修飾類,是@Data
的不可變形式, 相當於為成員變數新增final
宣告, 只提供getter
方法, 而不提供setter
方法,然後還有 equals/hashCode/toString
方法,以及一個包含所有引數的構造方法。
用在類、構造器、方法上,為你提供複雜的builder APIs,讓你可以像如下方式呼叫
Person.builder().name("A dam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build()
舉個栗子:
import lombok.Builder; import java.util.Set; @Builder public class BuilderExample { private String name; private int age; }
反編譯程式碼如下:
package tutorial.lombok; public class BuilderExample { public static class BuilderExampleBuilder { private String name; private int age; public BuilderExampleBuilder name(String name) { this.name = name; return this; } public BuilderExampleBuilder age(int age) { this.age = age; return this; } public BuilderExample build() { return new BuilderExample(name, age); } public String toString() { return (new StringBuilder()).append("BuilderExample.BuilderExampleBuilder(name=").append(name).append(", age=").append(age).append(")").toString(); } BuilderExampleBuilder() { } } private String name; private int age; BuilderExample(String name, int age) { this.name = name; this.age = age; } public static BuilderExampleBuilder builder() { return new BuilderExampleBuilder(); } }
注意:
使用@Singular
註解的集合屬性名必須使用s結尾, lombok
會將屬性名結尾的s去掉,剩餘的名字會作為方法名, 向這個集合中新增元素。
@Builder
的引數builderClassName
設定生成的builder方法名,
buildMethodName 設定
build方法名,
builderMethodName設定
builderMethod`方法名。
比如
@Builder(builderClassName = "GBuilder", buildMethodName = "buildG", builderMethodName = "GBuilder"
自動拋受檢異常, 而無需顯式在方法上使用throws語句。
用在方法上,將方法宣告為同步的,並自動加鎖,而鎖物件是一個私有的屬性 LOCK,而java中的synchronized
關鍵字鎖物件是this
,鎖在this
或者自己的類物件上存在副作用,就是你不能阻止非受控程式碼去鎖this或者類物件,這可能會導致競爭條件或者其它執行緒錯誤。
舉個栗子:
import lombok. Synchronized; public class SynchronizedExample { private final Object readLock = new Object() ; @Synchronized public static void hello() { System. out. println("world") ; } @Synchronized("readLock") public void foo() { System. out. println("bar") ; } }
反編譯程式碼如下:
public class SynchronizedExample { private static 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") ; } } }
可以替代經典的Double Check Lock樣板程式碼。
舉個栗子:
import lombok.Getter; 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; } }
反編譯程式碼如下,
import java.util.concurrent.atomic.AtomicReference; public class GetterLazyExample { private final AtomicReference cached = new AtomicReference(); public GetterLazyExample() { } private double[] expensive() { double result[] = new double[0xf4240]; for (int i = 0; i < result.length; i++) result[i] = Math.asin(i); return result; } public double[] getCached() { Object value = cached.get(); if (value == null) synchronized (cached) { value = cached.get(); if (value == null) { double actualValue[] = expensive(); value = actualValue != null ? ((Object) (actualValue)) : ((Object) (cached)); cached.set(value); } } return (double[])(double[])(value != cached ? value : null); } }
根據不同的註解生成不同型別的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) ;
舉個栗子,
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"); } }
@CommonsLog(topic="CounterLog")
這條語句會翻譯成這樣
private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog("CounterLog");
以上就是減少程式碼開發工作的Java庫lombok使用學習的詳細內容,更多關於Java lombok庫減少程式碼開發的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45