Lombok是什么
Lombok是一個(gè)旨在減少代碼開(kāi)發(fā)工作的Java庫(kù)。它提供了一些簡(jiǎn)單的注解,并以此來(lái)消除java中臃腫的模版代碼,比如 pojo 中最常見(jiàn)的?setter/getter
?方法, 比如?toString
?方法, 比如?equals
?方法等等,還可以幫助我們關(guān)閉流,即使 JDK7 中已經(jīng)有了 TWR 特性,但這個(gè)包很值得一試。
通過(guò)幾個(gè)簡(jiǎn)單的注解,將模版代碼在編譯時(shí)寫(xiě)入程序。在 Eclipse 中,生成的方法可以在 Outline 窗口中查看,但在源代碼中是沒(méi)有痕跡的
安裝
首先去?lombok 官網(wǎng)下載jar 包。
只是把 jar 包下載下來(lái)并導(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)要說(shuō)一下常用的幾個(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;// 可以指定訪問(wèn)權(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ù)組,在寫(xiě) toString
方法時(shí)使用了 Arrays
類(lèi)的 靜態(tài)方法 deepToString
。
來(lái)看 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)容全部打印出來(lái)。
exclude 參數(shù)
可以指定哪些屬性不出現(xiàn)在 toString
方法中, 比如 exclude={"id", "name"}
doNotUseGetters 參數(shù)
當(dāng)類(lèi)中有成員變量的 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
的格式來(lái)生成 toString
方法的,但是將該參數(shù)設(shè)置為 false
后(默認(rèn)是 true),就不會(huì)顯示 fieldName
了,而只是生成 fieldValue
, 比如
public String toString() { return "ToStringExample(" + getId() + ", " + getName() + ", " + Arrays.deepToString(getTags()) + ")"; }
callSuper 參數(shù)
若類(lèi) A 是類(lèi) B 的子類(lèi),那么在 A 類(lèi)重寫(xiě) toString
時(shí),若把該參數(shù)設(shè)置為 true
,會(huì)加入下面這段代碼,即也會(huì)把父類(lèi) B 的 toString
也寫(xiě)入。
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
用在類(lèi)上,用于生成 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
用來(lái)指定參與的變量,其他的跟 @ToString
注解類(lèi)似。
@Data
該注解用于修飾類(lèi),會(huì)自動(dòng)生成getter/setter
方法, 以及重寫(xiě)equals()
, hashcode()
和toString()
方法。
@Cleanup
該注解可以用來(lái)自動(dòng)管理資源,用在局部變量之前,在當(dāng)前變量范圍內(nèi)即將執(zhí)行完畢退出之前會(huì)自動(dòng)清理資源, 自動(dòng)生成try­finally
這樣的代碼來(lái)關(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è)注解修飾在類(lèi)上。
@NoArgsConstructor
用于生成一個(gè)無(wú)參構(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
該注解用于修飾類(lèi),是@Data
的不可變形式, 相當(dāng)于為成員變量添加final
聲明, 只提供getter
方法, 而不提供setter
方法,然后還有 equals/hashCode/toString
方法,以及一個(gè)包含所有參數(shù)的構(gòu)造方法。
@builder
用在類(lèi)、構(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)拋受檢異常, 而無(wú)需顯式在方法上使用throws語(yǔ)句。
@Synchronized
用在方法上,將方法聲明為同步的,并自動(dòng)加鎖,而鎖對(duì)象是一個(gè)私有的屬性 LOCK,而java中的synchronized
關(guān)鍵字鎖對(duì)象是this
,鎖在this
或者自己的類(lèi)對(duì)象上存在副作用,就是你不能阻止非受控代碼去鎖this或者類(lèi)對(duì)象,這可能會(huì)導(dǎo)致競(jìng)爭(zhēng)條件或者其它線(xiàn)程錯(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ù)不同的注解生成不同類(lèi)型的log對(duì)象, 但是實(shí)例名稱(chēng)都是log, 有六種可選實(shí)現(xiàn)類(lèi)
@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");
The above is the detailed content of How to use Java library lombok and annotations. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

The settings.json file is located in the user-level or workspace-level path and is used to customize VSCode settings. 1. User-level path: Windows is C:\Users\\AppData\Roaming\Code\User\settings.json, macOS is /Users//Library/ApplicationSupport/Code/User/settings.json, Linux is /home//.config/Code/User/settings.json; 2. Workspace-level path: .vscode/settings in the project root directory

To correctly handle JDBC transactions, you must first turn off the automatic commit mode, then perform multiple operations, and finally commit or rollback according to the results; 1. Call conn.setAutoCommit(false) to start the transaction; 2. Execute multiple SQL operations, such as INSERT and UPDATE; 3. Call conn.commit() if all operations are successful, and call conn.rollback() if an exception occurs to ensure data consistency; at the same time, try-with-resources should be used to manage resources, properly handle exceptions and close connections to avoid connection leakage; in addition, it is recommended to use connection pools and set save points to achieve partial rollback, and keep transactions as short as possible to improve performance.

DependencyInjection(DI)isadesignpatternwhereobjectsreceivedependenciesexternally,promotingloosecouplingandeasiertestingthroughconstructor,setter,orfieldinjection.2.SpringFrameworkusesannotationslike@Component,@Service,and@AutowiredwithJava-basedconfi

itertools.combinations is used to generate all non-repetitive combinations (order irrelevant) that selects a specified number of elements from the iterable object. Its usage includes: 1. Select 2 element combinations from the list, such as ('A','B'), ('A','C'), etc., to avoid repeated order; 2. Take 3 character combinations of strings, such as "abc" and "abd", which are suitable for subsequence generation; 3. Find the combinations where the sum of two numbers is equal to the target value, such as 1 5=6, simplify the double loop logic; the difference between combinations and arrangement lies in whether the order is important, combinations regard AB and BA as the same, while permutations are regarded as different;

java.lang.OutOfMemoryError: Javaheapspace indicates insufficient heap memory, and needs to check the processing of large objects, memory leaks and heap settings, and locate and optimize the code through the heap dump analysis tool; 2. Metaspace errors are common in dynamic class generation or hot deployment due to excessive class metadata, and MaxMetaspaceSize should be restricted and class loading should be optimized; 3. Unabletocreatenewnativethread due to exhausting system thread resources, it is necessary to check the number of threads, use thread pools, and adjust the stack size; 4. GCoverheadlimitexceeded means that GC is frequent but has less recycling, and GC logs should be analyzed and optimized.

fixture is a function used to provide preset environment or data for tests. 1. Use the @pytest.fixture decorator to define fixture; 2. Inject fixture in parameter form in the test function; 3. Execute setup before yield, and then teardown; 4. Control scope through scope parameters, such as function, module, etc.; 5. Place the shared fixture in conftest.py to achieve cross-file sharing, thereby improving the maintainability and reusability of tests.

TheJVMenablesJava’s"writeonce,runanywhere"capabilitybyexecutingbytecodethroughfourmaincomponents:1.TheClassLoaderSubsystemloads,links,andinitializes.classfilesusingbootstrap,extension,andapplicationclassloaders,ensuringsecureandlazyclassloa

Use classes in the java.time package to replace the old Date and Calendar classes; 2. Get the current date and time through LocalDate, LocalDateTime and LocalTime; 3. Create a specific date and time using the of() method; 4. Use the plus/minus method to immutably increase and decrease the time; 5. Use ZonedDateTime and ZoneId to process the time zone; 6. Format and parse date strings through DateTimeFormatter; 7. Use Instant to be compatible with the old date types when necessary; date processing in modern Java should give priority to using java.timeAPI, which provides clear, immutable and linear
