lombok 簡化 Java 程式碼
title: lombok 簡化 Java 程式碼
date: 2018-10-20 20:32:19
tags: lombok
author :辰砂tj
1.介紹
Lombok 是一種 Java 實用工具,可用來幫助開發人員消除 Java 的冗長,尤其是對於簡單的 Java 物件(POJO)。它通過註解實現這一目的。Lombok官網:https://projectlombok.org
2.idea使用
1.引入依賴
在專案中新增Lombok依賴jar,在pom檔案中新增如下部分。(不清楚版本可以在Maven倉庫中搜索)
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.18</version> <scope>provided</scope> </dependency>
2.idea外掛
3.註解的說明
@NonNull
or: How I learned to stop worrying and love the NullPointerException.
該註解使用在屬性上,該註解用於屬的非空檢查,當放在setter方法的欄位上,將生成一個空檢查,如果為空,則丟擲NullPointerException。
該註解會預設是生成一個無參構造。
public class User implements Serializable { private static final long serialVersionUID = 1L; private Integer uid; @NonNull @Setter @Getter private String username; private boolean flag; }
如果測試的時候username為空的情況下結果如下:
Exception in thread "main" java.lang.NullPointerException: username at com.taojian.tblog.lombok.User.setUsername(User.java:28) at com.taojian.tblog.lombok.Test.main(Test.java:15)
@Cleanup
Automatic resource management: Call your close() methods safely with no hassle.
該註解使用在屬性前,該註解是用來保證分配的資源被釋放。在本地變數上使用該註解,任何後續程式碼都將封裝在try/finally中,確保當前作用於中的資源被釋放。預設@Cleanup清理的方法為close,可以使用value指定不同的方法名稱
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(); } } } }
使用後:
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); } } }
@Getter/@Setter
Never write public int getFoo() {return foo;} again.
@Getter 就相對於是屬性的get()方法,@Setter就相當於屬性的set()方法。
The generated getter/setter method will be public unless you explicitly specify an AccessLevel, as shown in the example below. Legal access levels are PUBLIC, PROTECTED, PACKAGE, and PRIVATE.
這句話的意思就是可以指定設定的getter,setter的方法的許可權, @Setter(AccessLevel.PROTECTED) 這個就表示是一個protected屬性。
@Setter(AccessLevel.PROTECTED) private String name; /** * Changes the name of this person. * * @param name The new value. */ protected void setName(String name) { this.name = name; }
使用前:
public class User implements Serializable { private static final long serialVersionUID = 1L; private Integer uid; private String username; private String password; public Integer getUid() { return uid; } public String getUsername() { return username; } public String getPassword() { return password; } public void setUid(Integer uid) { this.uid = uid; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } }
使用後:
@Getter @Setter public class User implements Serializable { private static final long serialVersionUID = 1L; private Integer uid; private String username; private String password; }
@ToString
No need to start a debugger to see your fields: Just let lombok generate a toString for you!
1、如果需要可以通過註釋引數includeFieldNames來控制輸出中是否包含的屬性名稱。
2、可以通過exclude引數中包含欄位名稱,可以從生成的方法中排除特定欄位。
3、可以通過callSuper引數控制父類的輸出。
@ToString(exclude="column")
意義:排除column列所對應的元素,即在生成toString方法時不包含column引數;
@ToString(exclude={"column1","column2"})
意義:排除多個column列所對應的元素,其中間用英文狀態下的逗號進行分割,即在生成toString方法時不包含多個column引數;
@ToString(of="column")
意義:只生成包含column列所對應的元素的引數的toString方法,即在生成toString方法時只包含column引數;;
@ToString(of={"column1","column2"})
意義:只生成包含多個column列所對應的元素的引數的toString方法,其中間用英文狀態下的逗號進行分割,即在生成toString方法時只包含多個column引數;
使用前:
public class User implements Serializable { private static final long serialVersionUID = 1L; private Integer uid; private String username; private String password; @Override public String toString() { return super.toString(); } }
使用後:
@ToString public class User implements Serializable { private static final long serialVersionUID = 1L; private Integer uid; private String username; private String password;
@EqualsAndHashCode
Equality made easy: Generates hashCode and equals implementations from the fields of your object..
可以使用@EqualsAndHashCodelombok生成equals(Object other)和hashCode()方法的實現來註釋任何類定義
作用於類,自動重寫類的equals()、hashCode()方法。常用的引數有exclude(指定方法中不包含的屬性)、callSuper(方法中是否包含父類ToString()方法返回的值)
使用前:
使用後:
import lombok.EqualsAndHashCode; @EqualsAndHashCode public class EqualsAndHashCodeExample { private transient int transientVar = 10; private String name; private double score; @EqualsAndHashCode.Exclude private Shape shape = new Square(5, 10); private String[] tags; @EqualsAndHashCode.Exclude private int id; public String getName() { return this.name; } // 因為有繼承的關係,所以要設定true,如果沒有,只繼承了Object類的時候,就會報錯 @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; } } }
使用後:
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 and @AllArgsConstructor
Constructors made to order: Generates constructors that take no arguments, one argument per final / non-nullfield, or one argument for every field.
@NoArgsConstructor 相對於:
public User(){}
@RequiredArgsConstructor 該註解使用在類上,使用類中所有帶有 @NonNull 註解的或者帶有 final 修飾的成員變數生成對應的構造方法。
@NoArgsConstructor 相對於:
public User(Integer uid, String username, boolean flag) { this.uid = uid; this.username = username; this.flag = flag; }
@Data
All together now: A shortcut for @ToString, @EqualsAndHashCode, @Getter on all fields, and @Setter on all non-final fields, and @RequiredArgsConstructor!
該註解使用在類上,該註解是最常用的註解,它結合了@ToString,@EqualsAndHashCode, @Getter和@Setter。本質上使用@Data註解,類預設@ToString和@EqualsAndHashCode以及每個欄位都有@Setter和@getter。該註解也會生成一個公共建構函式,可以將任何@NonNull和final欄位作為引數。
雖然@Data註解非常有用,但是它沒有與其他註解相同的控制粒度。@Data提供了一個可以生成靜態工廠的單一引數,將staticConstructor引數設定為所需要的名稱,Lombok自動生成的建構函式設定為私有,並提供公開的給定名稱的靜態工廠方法。
/** * @description: * @author: taojian * @create: 2018-09-30 22:32 * 實際上含有這些方法 * getUid * getUsername * isFlag 這裡是isFlag(),而不是getFlag() * setUid * setUsername * setFlag * equals * hashCode * canEqual * toString **/ @Data public class User implements Serializable { private static final long serialVersionUID = 1L; private Integer uid; private String username; private boolean flag; @Data public class User implements Serializable { private static final long serialVersionUID = 1L; private Integer uid; private String username; private boolean flag; }
@Value
Immutable classes made very easy.
這個註解用在 類 上,會生成含所有引數的構造方法,get 方法,此外還提供了equals、hashCode、toString 方法。 注意:沒有setter 類似@Data
/** * @description: * @author: taojian * @create: 2018-09-30 22:32 * User * getUid * getUsername * isFlag * equals * hashCode * toString * serialVersionUID * uid * username * flag **/ @Value public class User implements Serializable { private static final long serialVersionUID = 1L; private Integer uid; private String username; private boolean flag; }
@Builder
... and Bob's your uncle: No-hassle fancy-pants APIs for object creation!
Project Lombok的@Builder 是一種在不編寫樣板程式碼的情況下使用Builder模式的有用機制。我們可以將此註釋應用於 類 或方法。
在類上使用@Builder
/** * @description: * User * getUid * getUsername * isFlag * builder 這個方法是增加的方法 **/ @Getter @Builder public class User implements Serializable { private static final long serialVersionUID = 1L; private Integer uid; private String username; private boolean flag; }
public class Test { public static void main(String[] args) { Useruser = User.builder().username("taojian").flag(true).uid(1).build(); System.out.println(user.getUsername().equals("taojian")); // true } }
2. 在方法上使用@Builder
假設我們正在使用我們想要使用構建器構造的物件,但我們無法修改源或擴充套件類。
首先,讓我們使用Lombok的@Value註釋建立一個快速示例:
@Value final class ImmutableClient { private int id; private String name; }
現在我們有一個帶有兩個不可變成員的最終 類,它們的getter和一個all-arguments建構函式。
我們介紹瞭如何在Class上 使用@Builder,但我們也可以在方法上使用它。我們將使用此功能來解決無法修改或擴充套件ImmutableClient的問題。
接下來,我們將使用建立ImmutableClients的方法建立一個新類:
class ClientBuilder { @Builder(builderMethodName = "builder") public static ImmutableClient newClient(int id, String name) { return new ImmutableClient(id, name); } }
這個註解建立了一個名為法生成器()是返回一個生成器來建立ImmutableClients。
現在我們可以構建一個ImmutableClient:
ImmutableClient testImmutableClient = ClientBuilder.builder() .name("foo") .id(1) .build(); assertThat(testImmutableClient.getName()) .isEqualTo("foo"); assertThat(testImmutableClient.getId()) .isEqualTo(1);
@SneakyThrows
To boldly throw checked exceptions where no one has thrown them before!
該註解使用在方法上,這個註解用在 方法 上,可以將方法中的程式碼用 try-catch 語句包裹起來,捕獲異常並在 catch 中用 Lombok.sneakyThrow(e) 把異常丟擲,可以使用 @SneakyThrows(Exception.class) 的形式指定丟擲哪種異常。該註解需要謹慎使用
使用前:
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); } } }
使用後:
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(); } }
@Synchronized
synchronized done right: Don't expose your locks.
該註解使用在類或者例項方法上,Synchronized在一個方法上,使用關鍵字可能會導致結果和想要的結果不同,因為多執行緒情況下會出現異常情況。Synchronized
關鍵字將在this示例方法情況下鎖定當前物件,或者class講臺方法的物件上多鎖定。這可能會導致死鎖現象。一般情況下建議鎖定一個專門用於此目的的獨立鎖,而不是允許公共物件進行鎖定。該註解也是為了達到該目的。
使用前:
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"); } } }
使用後:
mport 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"); } }
@Log @Slf4j
Captain's Log, stardate 24435.7: "What was that line again?"
日誌型別
experimental
Head to the lab: The new stuff we're working on.
@CommonsLog Creates private static final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(LogExample.class); @Flogger Creates private static final com.google.common.flogger.FluentLogger log = com.google.common.flogger.FluentLogger.forEnclosingClass(); @JBossLog Creates private static final org.jboss.logging.Logger log = org.jboss.logging.Logger.getLogger(LogExample.class); @Log Creates private static final java.util.logging.Logger log = java.util.logging.Logger.getLogger(LogExample.class.getName()); @Log4j Creates private static final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(LogExample.class); @Log4j2 Creates private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LogExample.class); @Slf4j Creates private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogExample.class); @XSlf4j Creates private static final org.slf4j.ext.XLogger log = org.slf4j.ext.XLoggerFactory.getXLogger(LogExample.class);
使用前:
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.severe("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"); } }
使用後:
import lombok.extern.java.Log; import lombok.extern.slf4j.Slf4j; @Log public class LogExample { public static void main(String... args) { log.severe("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"); } }
參考文章連結:
https://www.baeldung.com/lombok-builder
https://blog.csdn.net/motui/article/details/79012846
https://blog.csdn.net/motui/article/details/79012846
https://projectlombok.org/
https://segmentfault.com/a/1190000005133786