摘要:不久前發(fā)現(xiàn)有一個(gè)第三方庫可以在一定程度上幫助我們從體力勞動(dòng)中解救出來,它就是。來看自動(dòng)生成的方法中對于數(shù)組采用的是。檢查傳入對象是否為,若為,則拋出異常。比如自動(dòng)拋受檢異常,而無需顯式在方法上使用語句。
前言
Laziness is a virtue!
每當(dāng)寫pojo類時(shí),都會重復(fù)寫一些setter/getter/toString方法等大量的模版代碼,無聊繁瑣卻又不得不做,這會讓這個(gè)類變得又臭又長,卻沒有多少實(shí)質(zhì)的東西。
不久前發(fā)現(xiàn)有一個(gè)java第三方庫可以在一定程度上幫助我們從體力勞動(dòng)中解救出來,它就是lombok。它提供了一些簡單的注解,并以此來消除java中臃腫的模版代碼。本文對于一些常用到的注解做了一個(gè)簡要的記錄,希望有更多的人enjoy it!
Lombok是一個(gè)旨在減少代碼開發(fā)工作的Java庫。它提供了一些簡單的注解,并以此來消除java中臃腫的模版代碼,比如 pojo 中最常見的 setter/getter 方法, 比如 toString 方法, 比如 equals 方法等等,還可以幫助我們關(guān)閉流,即使 JDK7 中已經(jīng)有了 TWR 特性,但這個(gè)包很值得一試。
通過幾個(gè)簡單的注解,將模版代碼在編譯時(shí)寫入程序。使用 eclipse 可以在 Outline 窗口看到生成的方法,但是在源碼里是干凈的.
安裝首先去 lombok 官網(wǎng)下載jar 包。
只是把 jar 包下載下來并導(dǎo)入工程中,會發(fā)現(xiàn) IDE 不識別它的注解,那怎么辦?
將 lombok.jar 復(fù)制到 eclipse.ini 所在的目錄下,然后編輯 eclipse.ini 文件, 在它的末尾插入以下兩行并保存:
-Xbootclasspath/a:lombok.jar -javaagent:lombok.jar
接著重啟 eclipse 就可以愉快地使用這個(gè)庫了。
對于 IDEA在 IntelliJ 的插件中心可以找到它。
QuickStartLombok 提供的注解不多,但都好用,簡要說一下常用的幾個(gè)。
@Setter/@Getter這兩個(gè)注解修飾成員變量,可用于生成 setter/gettter 模版代碼。
舉個(gè)栗子:
import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; public class Student { @Setter @Getter private String name; @Getter(AccessLevel.PROTECTED) private int age;// 可以指定訪問權(quán)限 @Setter @Getter private String[] hobbies; }
將字節(jié)碼文件反編譯后可以看到下面這段代碼
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; } }@ToString
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; }
我們發(fā)現(xiàn),對于數(shù)組,在寫 toString 方法時(shí)使用了 Arrays類的 靜態(tài)方法 deepToString。
來看 eclipse 自動(dòng)生成的 toString 方法:
@Override public String toString() { return "ToStringExample [name=" + name + ", tags=" + Arrays.toString(tags) + "]"; }
eclipse 中對于數(shù)組采用的是 Arrays.toString()。
區(qū)別:這兩個(gè)方法的區(qū)別是這樣的,對于多維數(shù)組,使用 toString 只能打印出內(nèi)部數(shù)組的名字,這時(shí)需要使用 deepToString 方法,它能將內(nèi)部數(shù)組的內(nèi)容全部打印出來。
可以指定哪些屬性不出現(xiàn)在 toString 方法中, 比如 exclude={"id", "name"}
doNotUseGetters 參數(shù)當(dāng)類中有成員變量的 getter 方法時(shí),生成 toString 方法會使用這些 getter 方法,比如
public String toString() { return "ToStringExample(name=" + getName() + ", tags=" + Arrays.deepToString(getTags()) + ")"; }
但是將該參數(shù)設(shè)置為 true 時(shí)(默認(rèn)為 false),生成 toString 方法時(shí)就不會使用 getter 方法,而是直接使用這些成員變量,比如
public String toString() { return "ToStringExample(name=" + this.name + ", tags=" + Arrays.deepToString(this.tags) + ")"; }includeFieldNames參數(shù)
原本是以 fieldName = fieldValue 的格式來生成 toString 方法的,但是將該參數(shù)設(shè)置為 false 后(默認(rèn)是 true),就不會顯示 fieldName 了,而只是生成 fieldValue, 比如
public String toString() { return "ToStringExample(" + getId() + ", " + getName() + ", " + Arrays.deepToString(getTags()) + ")"; }callSuper 參數(shù)
若類 A 是類 B 的子類,那么在 A 類重寫 toString 時(shí),若把該參數(shù)設(shè)置為 true,會加入下面這段代碼,即也會把父類 B 的 toString 也寫入。
super=" + super.toString()@NonNull
檢查傳入對象是否為 Null,若為null,則拋出NullPointerException異常。
舉個(gè)栗子
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(); } }@EqualsAndHashCode
用在類上,用于生成 equals 和 hashcode 方法。
舉個(gè)栗子
@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修飾的變量,不會參與。
參數(shù)參數(shù) of 用來指定參與的變量,其他的跟 @ToString 注解類似。
@Data該注解用于修飾類,會自動(dòng)生成getter/setter方法, 以及重寫equals(), hashcode()和toString()方法。
@Cleanup該注解可以用來自動(dòng)管理資源,用在局部變量之前,在當(dāng)前變量范圍內(nèi)即將執(zhí)行完畢退出之前會自動(dòng)清理資源, 自動(dòng)生成try-finally這樣的代碼來關(guān)閉流。
舉個(gè)栗子:
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/@AllArgsConstructor
這三個(gè)注解修飾在類上。
@NoArgsConstructor 用于生成一個(gè)無參構(gòu)造方法。
@RequiredArgsConstructor 會生成一個(gè)包含了被@NotNull標(biāo)識的變量的構(gòu)造方法。同樣可以設(shè)置生成構(gòu)造方法的權(quán)限,使用 access參數(shù)進(jìn)行設(shè)置。
@AllArgsConstructor 會生成一個(gè)包含所有變量, 同時(shí)如果變量使用了@NotNull,會進(jìn)行是否為空的校驗(yàn)。
舉個(gè)栗子:
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; } }
這與下面這段代碼是等價(jià)的,
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() {} } }@Value
該注解用于修飾類,是@Data的不可變形式, 相當(dāng)于為成員變量添加final聲明, 只提供getter方法, 而不提供setter方法,
然后還有 equals/hashCode/toString方法,以及一個(gè)包含所有參數(shù)的構(gòu)造方法。
用在類、構(gòu)造器、方法上,為你提供復(fù)雜的builder APIs,讓你可以像如下方式調(diào)用
Person.builder().name("A dam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build()
舉個(gè)栗子:
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結(jié)尾, lombok會將屬性名結(jié)尾的s去掉,剩余的名字會作為方法名, 向這個(gè)集合中添加元素。
@Builder 的參數(shù)builderClassName設(shè)置生成的builder方法名,buildMethodName 設(shè)置build方法名,builderMethodName設(shè)置builderMethod`方法名。
比如
@Builder(builderClassName = "GBuilder", buildMethodName = "buildG", builderMethodName = "GBuilder"@SneakyThrows
自動(dòng)拋受檢異常, 而無需顯式在方法上使用throws語句。
@Synchronized用在方法上,將方法聲明為同步的,并自動(dòng)加鎖,而鎖對象是一個(gè)私有的屬性 LOCK,而java中的synchronized關(guān)鍵字鎖對象是this,鎖在this或者自己的類對象上存在副作用,就是你不能阻止非受控代碼去鎖this或者類對象,這可能會導(dǎo)致競爭條件或者其它線程錯(cuò)誤。
舉個(gè)栗子:
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") ; } } }@Getter(lazy=true)
可以替代經(jīng)典的Double Check Lock樣板代碼。
舉個(gè)栗子:
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
根據(jù)不同的注解生成不同類型的log對象, 但是實(shí)例名稱都是log, 有六種可選實(shí)現(xiàn)類
@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) ;
舉個(gè)栗子,
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");
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/66428.html
摘要:下面隆重介紹簡介是一個(gè)解析的第三方庫,它提供了一套非常方便的,可使用,以及類的操作方法來取出和操作數(shù)據(jù)。一個(gè)文檔的對象模型文檔由多個(gè)和組成其繼承結(jié)構(gòu)如下繼承繼承繼承一個(gè)包含一個(gè)子節(jié)點(diǎn)集合,并擁有一個(gè)父。 前言 使用python寫爬蟲的人,應(yīng)該都聽過beautifulsoup4這個(gè)包,用來它來解析網(wǎng)頁甚是方便。那么在java里有沒有類似的包呢?當(dāng)然有啦!而且也非常好用。下面隆重介紹jso...
摘要:豐富的數(shù)據(jù)類型支持二進(jìn)制案例的及數(shù)據(jù)類型操作。原子的所有操作都是原子性的,同時(shí)還支持對幾個(gè)操作全并后的原子性執(zhí)行。豐富的特性還支持通知過期等等特性。的數(shù)據(jù)類型都是基于基本數(shù)據(jù)結(jié)構(gòu)的同時(shí)對程序員透明,無需進(jìn)行額外的抽象。 Redis 簡介 Redis 是完全開源免費(fèi)的,遵守BSD協(xié)議,是一個(gè)高性能的key-value數(shù)據(jù)庫。Redis 與其他 key - value 緩存產(chǎn)品有以下三個(gè)特...
摘要:使用可以大大減少代碼行數(shù),提高開發(fā)效率。提供了日志工具無參構(gòu)造器提供方法提供方法方法有參構(gòu)造器,參數(shù)按屬性定義順序傳入提供了空指針檢測,會拋出異常 lombok 是一個(gè)第三方工具,提供了一些注解功能,可以幫助我們消除冗余、臃腫的 Java 代碼,比如 POJO 的 getter/setter 方法、構(gòu)造方法、hashcode 方法等。lombok 在編譯時(shí)根據(jù)注解生成具體的代碼,在虛擬...
摘要:前言前端開發(fā)中會遇到一些頻繁的事件觸發(fā),比如的,等等,假如你對自己的代碼不做什么的處理,你會發(fā)現(xiàn)頁面卡頓觸發(fā)接口請求頻繁等問題,本文將淺析函數(shù)節(jié)流跟防抖實(shí)現(xiàn),一步一步逐漸揭開函數(shù)節(jié)流跟防抖的真面目 前言 前端開發(fā)中會遇到一些頻繁的事件觸發(fā),比如:window的scroll、resize;mousedown、mousemove,keyup、keydown等等,假如你對自己的代碼不做什么的...
閱讀 2118·2021-11-24 10:28
閱讀 1143·2021-10-12 10:12
閱讀 3350·2021-09-22 15:21
閱讀 691·2021-08-30 09:44
閱讀 1907·2021-07-23 11:20
閱讀 1155·2019-08-30 15:56
閱讀 1767·2019-08-30 15:44
閱讀 1490·2019-08-30 13:55