減少代碼開發(fā)工作的Java庫(kù)lombok及注解的使用學(xué)習(xí)
前言
Laziness is a virtue!
每當(dāng)寫pojo類時(shí),都會(huì)重復(fù)寫一些setter/getter/toString方法等大量的模版代碼,無聊繁瑣卻又不得不做,這會(huì)讓這個(gè)類變得又臭又長(zhǎng),卻沒有多少實(shí)質(zhì)的東西
Lombok是什么
Lombok是一個(gè)旨在減少代碼開發(fā)工作的Java庫(kù)。它提供了一些簡(jiǎn)單的注解,并以此來消除java中臃腫的模版代碼,比如 pojo 中最常見的 setter/getter 方法, 比如 toString 方法, 比如 equals 方法等等,還可以幫助我們關(guān)閉流,即使 JDK7 中已經(jīng)有了 TWR 特性,但這個(gè)包很值得一試。
通過幾個(gè)簡(jiǎn)單的注解,將模版代碼在編譯時(shí)寫入程序。使用 eclipse 可以在 Outline 窗口看到生成的方法,但是在源碼里是干凈的.
安裝
首先去 lombok 官網(wǎng)下載jar 包。
只是把 jar 包下載下來并導(dǎo)入工程中,會(huì)發(fā)現(xiàn) IDE 不識(shí)別它的注解,那怎么辦?
對(duì)于eclipse
將 lombok.jar 復(fù)制到 eclipse.ini 所在的目錄下,然后編輯 eclipse.ini 文件, 在它的末尾插入以下兩行并保存:
Xbootclasspath/a:lombok.jar javaagent:lombok.jar
接著重啟 eclipse 就可以愉快地使用這個(gè)庫(kù)了。
對(duì)于 IDEA
在 IntelliJ 的插件中心可以找到它。
QuickStart
Lombok 提供的注解不多,但都好用,簡(jiǎn)要說一下常用的幾個(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),對(duì)于數(shù)組,在寫 toString 方法時(shí)使用了 Arrays類的 靜態(tài)方法 deepToString。
來看 eclipse 自動(dòng)生成的 toString 方法:
@Override
public String toString() {
return "ToStringExample [name=" + name + ", tags=" + Arrays.toString(tags) + "]";
}eclipse 中對(duì)于數(shù)組采用的是 Arrays.toString()。
區(qū)別:這兩個(gè)方法的區(qū)別是這樣的,對(duì)于多維數(shù)組,使用 toString 只能打印出內(nèi)部數(shù)組的名字,這時(shí)需要使用 deepToString 方法,它能將內(nèi)部數(shù)組的內(nèi)容全部打印出來。
exclude 參數(shù)
可以指定哪些屬性不出現(xiàn)在 toString 方法中, 比如 exclude={"id", "name"}
doNotUseGetters 參數(shù)
當(dāng)類中有成員變量的 getter 方法時(shí),生成 toString 方法會(huì)使用這些 getter 方法,比如
public String toString() {
return "ToStringExample(name=" + getName() + ", tags=" + Arrays.deepToString(getTags()) + ")";
}但是將該參數(shù)設(shè)置為 true 時(shí)(默認(rèn)為 false),生成 toString 方法時(shí)就不會(huì)使用 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),就不會(huì)顯示 fieldName 了,而只是生成 fieldValue, 比如
public String toString() {
return "ToStringExample(" + getId() + ", " + getName() + ", " + Arrays.deepToString(getTags()) + ")";
}callSuper 參數(shù)
若類 A 是類 B 的子類,那么在 A 類重寫 toString 時(shí),若把該參數(shù)設(shè)置為 true,會(huì)加入下面這段代碼,即也會(huì)把父類 B 的 toString 也寫入。
super=" + super.toString()
@NonNull
檢查傳入對(duì)象是否為 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修飾的變量,不會(huì)參與。
參數(shù)
參數(shù) of 用來指定參與的變量,其他的跟 @ToString 注解類似。
@Data
該注解用于修飾類,會(huì)自動(dòng)生成getter/setter方法, 以及重寫equals(), hashcode()和toString()方法。
@Cleanup
該注解可以用來自動(dòng)管理資源,用在局部變量之前,在當(dāng)前變量范圍內(nèi)即將執(zhí)行完畢退出之前會(huì)自動(dòng)清理資源, 自動(dòng)生成tryfinally這樣的代碼來關(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 會(huì)生成一個(gè)包含了被@NotNull標(biāo)識(shí)的變量的構(gòu)造方法。同樣可以設(shè)置生成構(gòu)造方法的權(quán)限,使用 access參數(shù)進(jìn)行設(shè)置。
@AllArgsConstructor 會(huì)生成一個(gè)包含所有變量, 同時(shí)如果變量使用了@NotNull,會(huì)進(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)造方法。
@builder
用在類、構(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會(huì)將屬性名結(jié)尾的s去掉,剩余的名字會(huì)作為方法名, 向這個(gè)集合中添加元素。
@Builder 的參數(shù)builderClassName設(shè)置生成的builder方法名,buildMethodName 設(shè)置build方法名,builderMethodName設(shè)置builderMethod`方法名。
比如
@Builder(builderClassName = "GBuilder", buildMethodName = "buildG", builderMethodName = "GBuilder"
@SneakyThrows
自動(dòng)拋受檢異常, 而無需顯式在方法上使用throws語(yǔ)句。
@Synchronized
用在方法上,將方法聲明為同步的,并自動(dòng)加鎖,而鎖對(duì)象是一個(gè)私有的屬性 LOCK,而java中的synchronized關(guān)鍵字鎖對(duì)象是this,鎖在this或者自己的類對(duì)象上存在副作用,就是你不能阻止非受控代碼去鎖this或者類對(duì)象,這可能會(huì)導(dǎo)致競(jìng)爭(zhēng)條件或者其它線程錯(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對(duì)象, 但是實(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")
這條語(yǔ)句會(huì)翻譯成這樣
private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog("CounterLog");以上就是減少代碼開發(fā)工作的Java庫(kù)lombok使用學(xué)習(xí)的詳細(xì)內(nèi)容,更多關(guān)于Java lombok庫(kù)減少代碼開發(fā)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
CompletableFuture并行處理List分批數(shù)據(jù)demo
這篇文章主要介紹了CompletableFuture并行處理List分批數(shù)據(jù)實(shí)現(xiàn)實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11
Java替換int數(shù)組中重復(fù)數(shù)據(jù)的方法示例
這篇文章主要介紹了Java替換int數(shù)組中重復(fù)數(shù)據(jù)的方法,涉及java針對(duì)數(shù)組的遍歷、轉(zhuǎn)換、判斷等相關(guān)操作技巧,需要的朋友可以參考下2017-06-06
SpringCloud之熔斷監(jiān)控Hystrix Dashboard的實(shí)現(xiàn)
這篇文章主要介紹了SpringCloud之熔斷監(jiān)控Hystrix Dashboard的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
spring Boot與Mybatis整合優(yōu)化詳解
關(guān)于spring-boot與mybatis整合優(yōu)化方面的介紹,就是Mybatis-Spring-boot-starter的介紹,具體內(nèi)容詳情大家參考下本文2017-07-07

