天天看點

Java 開發工具–Lombok介紹

概述

在寫POJO代碼時,經常需要生成getter和setter方法,以及hashcode、tostring和equals等代碼。感覺甚是麻煩,雖然有Eclipse或者intellij IDEA快捷鍵能夠自動生成些代碼;代碼裡面充斥着這種沒有意義的片段,看着都覺得煩;另一方面,單元測試時,若是考察行覆寫率,這種POJO代碼勢必會增加分母的大小,降低代碼覆寫率。

偶然中,得知Lombok Project,通過使用注解,可以消除備援的java代碼。

官網介紹:

Project Lombok makes java a spicier language by adding ‘handlers’ that know how to build and compile simple, boilerplate-free, not-quite-java code.

如何使用

引入依賴即可:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <scope>provided</scope>
</dependency>      

Gradle項目的引入方式類似:

provided group: 'org.projectlombok', name: 'lombok', version: '1.16.18'      

在spring boot項目中,引入Lombok時沒有必要指定​

​<version>和<scope>​

​,spring boot已經自動配置好。

如何安裝

在IDEA中使用Lombok需要先安裝插件,快捷鍵 Ctrl + Alt + S,然後選擇 plugins——> browse repositories,搜尋 Lombok,install即可,安裝需要重新開機。

其次,Lombok是在編譯時期,自動生成所需方法的,是以需要開啟annotation processing;依舊是剛才的快捷鍵,可以搜尋"annotation processing",然後選擇"Enable annotation processing"。

注解

不完全統計:

@NonNull:辨別對象是否為空,為空則抛出異常
@Getter/@Setter:自動生成Getter/Setter方法
@ToString:覆寫tostring方法,可以添加限制條件
@EqualsAndHashCode:覆寫equal和hashCode方法,生成方法時隻會使用類中的非靜态和非transient成員變量
@Data:@Getter/@Setter, @ToString, @EqualAndHashCode,@NoArgsConstructor等組合
@Cleanup:用在變量前面,可以保證此變量代表的資源會被自動關閉,預設是調用資源的close()方法,如果該資源有其它關閉方法,可使用@Cleanup("methodName")來指定要調用的方法
@NoArgsConstructor/@RequiredArgsConstructor /@AllArgsConstructor:第二個注解使用類中所有帶有@NonNull注解的或帶有final修飾的非靜态成員變量生成對應的構造方法,
@Log:類注解,可以省去從日志工廠生成日志對象這一步,直接進行日志記錄,具體注解根據日志工具的不同而不同,同時,可以在注解中使用topic來指定生成log對象時的類名
@Builder:關于build模式,可以參考《Effective  java》這本書
@Value
@SneakyThrows
@Synchronized
@Accessors(chain = true),在生成 setter 方法時不傳回 void,而是傳回 this,目前類;      

執行個體代碼

@Getter & @Setter & @ToString

public class Person {
    private boolean employed;
    private String name;

    Person() {
    }

    public String say() {
        return this.getName();
    }

    public String toString() {
        return "Person(employed=" + this.isEmployed() + ", name=" + this.getName() + ")";
    }

    public boolean isEmployed() {
        return this.employed;
    }

    public void setEmployed(boolean employed) {
        this.employed = employed;
    }

    public String getName() {
        return this.name;
    }

    protected void setName(String name) {
        this.name = name;
    }
}      

如果使用Lombok提供的注解:

@ToString
 class Person {
    @Getter
    @Setter
    private boolean employed;
    @Getter
    @Setter(AccessLevel.PROTECTED)
    private String name;

    public String say() {
        return getName();
    }
}      

@Builder

這次先看看使用注解之前的java code:

@Builder
public class BuilderExample {
    private String name;
    private int age;
}      

再看看其經過編譯之後的java code:

import java.beans.ConstructorProperties;

public class BuilderExample {
    private String name;
    private int age;

    @ConstructorProperties({"name", "age"})
    BuilderExample(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public static BuilderExample.BuilderExampleBuilder builder() {
        return new BuilderExample.BuilderExampleBuilder();
    }

    public static class BuilderExampleBuilder {
        private String name;
        private int age;

        BuilderExampleBuilder() {
        }

        public BuilderExample.BuilderExampleBuilder name(String name) {
            this.name = name;
            return this;
        }

        public BuilderExample.BuilderExampleBuilder age(int age) {
            this.age = age;
            return this;
        }

        public BuilderExample build() {
            return new BuilderExample(this.name, this.age);
        }

        public String toString() {
            return "BuilderExample.BuilderExampleBuilder(name=" + this.name + ", age=" + this.age + ")";
        }
    }
}      

使用:

​​

​UserVO user = UserVO.builder().id(3).username("chifanshuijiao").build();​

​ 注意:需要額外增加兩個注解:

@NoArgsConstructor
@AllArgsConstructor      

@Data

先看使用注解的類:

@Data
public class User {
    private Integer id;
    private String password;
}      

編譯之後的類長這樣:

public class User {
    private Integer id;
    private String password;

    public User() {
    }

    public Integer getId() {
        return this.id;
    }

    public String getPassword() {
        return this.password;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof User)) {
            return false;
        } else {
            User other = (User)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                Object this$id = this.getId();
                Object other$id = other.getId();
                if (this$id == null) {
                    if (other$id != null) {
                        return false;
                    }
                } else if (!this$id.equals(other$id)) {
                    return false;
                }

                Object this$password = this.getPassword();
                Object other$password = other.getPassword();
                if (this$password == null) {
                    if (other$password != null) {
                        return false;
                    }
                } else if (!this$password.equals(other$password)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(Object other) {
        return other instanceof User;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $id = this.getId();
        int result = result * 59 + ($id == null ? 43 : $id.hashCode());
        Object $password = this.getPassword();
        result = result * 59 + ($password == null ? 43 : $password.hashCode());
        return result;
    }

    public String toString() {
        return "User(id=" + this.getId() + ", password=" + this.getPassword() + ")";
    }
}      

更多注解的用法,請參考​​官網​​。

​lombok.config​

​​config官方文檔​​​ 檢視目前版本的lombok所支援的配置項使用指令工具config

​java -jar lombok.jar config -g --verbose​

​ cofing工具檢視某個配置檔案所有的配置項

​java -jar lombok.jar config lombok.config​

示例:

# Tell the configuration system it should stop looking for other configuration files (default: false).
# 指明lombok的根目錄為目前配置檔案所在目錄
# 配置檔案是分層的,原則是接近源檔案的配置設定優先。在根目錄的子目錄中可以建立lombok.config配置檔案,來覆寫根目錄的配置檔案(隻覆寫配置項相同的配置,其他繼承根目錄的配置,若沒有顯式配置則使用預設值)
config.stopBubbling = true
# Generate setters that return 'this' instead of 'void' (default: false).
lombok.accessors.chain = true
# 使用不帶字首的簡單方式生成setter和getter,即使用原始的字段名稱省略get和set字首
lombok.accessors.fluent=true
# 跳過添加一個@java.bean.ConstructorProperties生成的構造器
lombok.anyConstructor.suppressConstructorProperties=true
# Don't call the getters but use the fields directly in the generated toString method (default = false).
lombok.toString.doNotUseGetters = true
# When generating toString for classes that extend something (other than Object), either automatically take into account superclass implementation (call), or don't (skip), or warn and don't (warn). (default = warn).
lombok.toString.callSuper = CALL      

要求:lombok 1.14+

原理

采用JSR269所提出的插入式注解處理(Pluggable Annotation Processing),并結合動态代碼生成技術所開發的。如下圖所示:

Java 開發工具–Lombok介紹

圖示為 javac 的編譯過程,java檔案首先通過進行解析建構出一個AST,然後執行注解處理,最後經過分析優化生成二進制的.class檔案。

Annotation Processing 是在解析和生成之間的一個步驟。

Java 開發工具–Lombok介紹

上圖是 Lombok 處理流程,在Javac 解析成抽象文法樹之後(AST),Lombok 根據自己的注解處理器,動态的修改 AST,增加新的節點(所謂代碼),最終通過分析和生成位元組碼。

其他注解

Wither

Java 開發工具–Lombok介紹

val

無憂的final本地變量

NonNull

Cleanup

自動的資源管理:安全調用你的close() 方法,無需任何麻煩。

Lombok缺點

參考