Lombok神器帶你飛(簡化POJO)

前言

遇到殘暴的大佬,心裏不由得爲代碼暗暗揪了心,不過擼碼殘暴起來,也是感覺到了一絲絲的爽~

今天爲大家介紹一個神器:Lombok。

希望各種各樣的神器帶來便捷的同時也爲我們帶來更多的Money~


本文目標

希望閱讀完本文的童鞋,可以快速入手項目,讓我們一起殘暴的擼碼!

思考一下

首先舉三個例子:

Case 1:屬性私有,設置其 get / set

package com.hlq.lombokdemo;

/**
 * author : HLQ
 * e-mail : [email protected]
 * time   : 2018/04/10
 * desc   : 曾經,我們是這樣玩~
 * version: 1.0
 */
public class UserBean1 {

    private String userName;
    private int userAge;
    private String userAddress;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public int getUserAge() {
        return userAge;
    }

    public void setUserAge(int userAge) {
        this.userAge = userAge;
    }

    public String getUserAddress() {
        return userAddress;
    }

    public void setUserAddress(String userAddress) {
        this.userAddress = userAddress;
    }
}

Case 2:設置屬性公開,節省 get / set

package com.hlq.lombokdemo;

/**
 * author : HLQ
 * e-mail : [email protected]
 * time   : 2018/04/10
 * desc   : 偷奸耍滑 設置屬性公有
 * version: 1.0
 */
public class UserBean2 {

    public String userName;
    public int userAge;
    public String userAddress;

}

Case 3:各種常用類型實例

    private String userName;
    private int userAge;
    private String userAddress;

    private ArrayList userList=new ArrayList();
    private HashMap<String,String> userMap=new HashMap<>();
    private ArrayList<HashMap<String,String>> stuList=new ArrayList<>();

看到這裏,不知大家有沒有感覺出一點點什麼?


是的,Case 1 和 Case 2的區別在於 節省了部分的 get / set,但是同樣也將我們私有屬性暴露給外界。

那麼,有沒有一種又能省事兒,又相對安全的呢?

有的童鞋說,註解啊,不過一般就這個小玩意也沒必要吧。

Yes,手寫註解,確實有點煩,當然咯,大佬略過勒~那麼,我們何嘗不能使用一個So easy的插件呢?


Lombok隆重登場

首先貼出官方地址:

https://projectlombok.org/features/val
接着貼出GitHub地址:

https://github.com/mplushnikov/lombok-intellij-plugin
相信有興趣的童鞋已經迫不及待的去官網學習了,這裏LZ爲了加深理解,自己再巴拉巴拉~


使用前準備

Lombok,一款簡單易用方便的小神器,使用前,需要進行一些簡單的小配置,跟我來~

Step 1:安裝《Lombok》插件,如下圖:


Step 2:添加遠程依賴

implementation “org.projectlombok:lombok:1.16.20”
ok,就這麼簡單,easy~

如果在同步的過程中,提示如下異常:

Annotation processors must be explicitly declared now. The following dependencies on the compile classpath are found to contain annotation processor. Please add them to the annotationProcessor configuration.
只需要在app下build文件添加如下即可:

    defaultConfig {
        javaCompileOptions { annotationProcessorOptions { includeCompileClasspath = true } }
    }

下面,讓我們一起來學習有關 Lombok 相關知識點~

搞起來,搞起來


一、@Getter 、@Setter 以及 AccessLevel

首先要明確以下幾點:

如果在Class上設置,則默認添加類中所有屬性的 get / set 方法;

如果單獨給某一個屬性設置 get / set,則只會生成對應屬性的 get / set 方法;

Lombok 同樣爲我們提供了一些可以設置當前類似訪問權限或者禁止生成某個方法函數,它就是 AccessLevel,其中它對應以下倆種場景:

PUBLIC,PROTECTED,PACKAGE,和PRIVATE:設置訪問級別;

NONE:禁止生成某個對應的 get / set

下面一起來看示例:

package com.hlq.lombokdemo;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;

/**
 * author : HLQ
 * e-mail : [email protected]
 * time   : 2018/04/11
 * desc   : @Getter @Setter 使用
 * version: 1.0
 */
public class GetSetBean {

    // 生成get/set
    @Getter
    @Setter
    private String name;

    // 禁止生成set
    @Setter(AccessLevel.NONE)
    private int age;

}

現在我們設置爲生成屬性 “name” 的 get 以及 set 以及禁止生成屬性 “age”,我們來一起驗證一下吧!

    GetSetBean getSetBean = new GetSetBean();
    getSetBean.getName();
    getSetBean.setName("GetSetBean");
    getSetBean.getAge();

老鐵可能會說了,無圖不真實! 
那好,上圖~ 


當然,你可以直接在類名上方添加 @Getter 以及 @Setter,以便直接爲當前類生成 get 以及 set。

package com.hlq.lombokdemo;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;

/**
 * author : HLQ
 * e-mail : [email protected]
 * time   : 2018/04/11
 * desc   : @Getter @Setter 使用
 * version: 1.0
 */
@Getter
@Setter
public class GetSetBean {

    private String name;

    private int age;

}
 

相比之下是不是少了很多?

二、@ToString

任何類定義都可以用@ToStringLombok 註釋來生成該 toString() 方法的實現。默認情況下,會按順序打印名稱和字段,並以逗號分隔。
這裏需要明確以下幾點:

exclude:代表你不想看到某個或者某些參數的輸出;

of:代表你只想看某個或者某些參數的輸出

lombok.toString.includeFieldNames= [ true| false](默認值:true) 
通常,Lombok 以每個字段的形式爲 toString 響應生成一個片段fieldName = fieldValue。如果此設置設置爲false,Lombok 將省略該字段的名稱,並簡單地部署所有字段值的逗號分隔列表。includeFieldNames 如果明確指定了註釋參數“ ‘,則優先於此設置。

lombok.toString.doNotUseGetters= [ true| false](默認值:false) 
如果設置爲true,Lombok 將在生成 toString 方法時直接訪問字段,而不是使用getter(如果可用)。doNotUseGetters如果明確指定了註釋參數“ ‘,則優先於此設置。
lombok.toString.flagUsage= [ warning| error](默認:未設置) 
@ToString如果配置, Lombok將標記任何用作警告或錯誤。

具有 exclude 並 of 產生警告; exclude 在這種情況下,該參數將被忽略

假定一個實例,如下:

    ToStringBean toStringBean = new ToStringBean();
    toStringBean.str = "ToStringBean";
    toStringBean.numStr = "100";
    toStringBean.nameStr = "賀利權";
    Log.e(TAG, toStringBean.toString());

Case 1:設置@ToString

@ToString
public class ToStringBean
1
2
則默認打印所有,中間以逗號隔開,如下:

ToStringBean(str=ToStringBean, numStr=100, nameStr=賀利權)
Case 2:設置 exclude 屬性

@ToString(exclude = "str") // 這裏注意,可屏蔽一個,也可屏蔽多個
public class ToStringBean {

則打印輸入除 “str” 之外的屬性:

ToStringBean(numStr=100, nameStr=賀利權)
Case 3:設置 of 屬性

@ToString(of = "nameStr")
public class ToStringBean {

則打印指定屬性內容:

ToStringBean(nameStr=賀利權)
Case 4:同時設置 exclude 以及 of 屬性

@ToString(exclude = "str", of = "nameStr")
public class ToStringBean {

首先編譯會提示如下警告:


其次,只會遵循 of 屬性:

ToStringBean(nameStr=賀利權)
三、@EqualsAndHashCode

任何實體類均可以用 @EqualsAndHashCodeLombok 註釋來生成 equals(Object other) 和 hashCode() 方法的實現。 
默認情況下,它將使用所有非靜態非瞬態字段,但是可以通過 exclude 在註釋的可選參數來排除更多屬性。或者,您可以通過在 of 參數來指定所希望使用的字段。
下面一起來看實例:

package com.hlq.lombokdemo.testbean;

import lombok.EqualsAndHashCode;

/**
 * author : HLQ
 * e-mail : [email protected]
 * time   : 2018/04/11
 * desc   : 玩轉@EqualsAndHashCode
 * version: 1.0
 */
@EqualsAndHashCode
public class EqualsAndHashCodeBean {

}

測試如下:

    EqualsAndHashCodeBean equalsAndHashCodeBean = new EqualsAndHashCodeBean();
    Log.e(TAG, equalsAndHashCodeBean.equals("123") + "");
    Log.e(TAG, equalsAndHashCodeBean.hashCode() + "");
    Log.e(TAG, equalsAndHashCodeBean.hashCode() + "");

結果如下:


看到這裏,大家會不會在想,這倆個有啥用呢?

下面考大家個當年背的滾瓜爛熟一個題:

== 和 .equals() 區別?
== 比較的是變量(棧)內存中存放的對象的(堆)內存地址;

equals用來比較的是兩個對象的內容是否相等;

而hashCode(),可以理解爲,它會默認生成一個隨機數,而倆者相比較,則是比較這個隨機數。不知道大家可否明白?

下面引用一哥兒們解釋,希望大家能明白:

hashCode() 方法和 equal() 方法的作用其實一樣,在 Java 裏都是用來對比兩個對象是否相等一致。 
重寫的 equal()裏一般比較的比較全面比較複雜,這樣效率就比較低,而利用 hashCode() 進行對比,則只要生成一個 hash 值進行比較就可以了,效率很高。 
但是,hashCode() 並不是完全可靠,有時候不同的對象他們生成的 hashcode 也會一樣(生成hash值得公式可能存在的問題),所以 hashCode() 只能說是大部分時候可靠,並不是絕對可靠,所以我們可以得出:
equal()相等的兩個對象他們的hashCode()肯定相等,也就是用equal()對比是絕對可靠的; 

hashCode()相等的兩個對象他們的equal()不一定相等,也就是hashCode()不是絕對可靠的。
So,我們可以得出以下結論:

所有對於需要大量並且快速的對比的話如果都用equal()去做顯然效率太低,所以解決方式是,每當需要對比的時候,首先用hashCode()去對比,如果hashCode()不一樣,則表示這兩個對象肯定不相等(也就是不必再用equal()去再對比了),如果hashCode()相同,此時再對比他們的equal(),如果equal()也相同,則表示這兩個對象是真的相同了,這樣既能大大提高了效率也保證了對比的絕對正確性!

四、@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor

小標題上的三個屬性,均可以生成構造函數,那麼他們之間有何不同呢?一起來看~

@NoArgsConstructor:生成無參數構造函數;

@RequiredArgsConstructor:爲每個需要特殊處理的字段生成一個帶有1個參數的構造函數,且生成的構造爲私有,需要通過設置 staticName 來獲取訪問;

@AllArgsConstructor:爲您的類中的每個字段生成一個帶有1個參數的構造函數。

實體如下:

package com.hlq.lombokdemo.testbean;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;

/**
 * author : HLQ
 * e-mail : [email protected]
 * time   : 2018/04/11
 * desc   : @NoArgsConstructor,@RequiredArgsConstructor,@AllArgsConstructor 使用
 * version: 1.0
 */
@AllArgsConstructor
public class ConstructorBean {

    private String userName;
    private String userAddress;

    @NoArgsConstructor
    public static class Test1 {

        private String testName;
        private String testPage;

    }

    @RequiredArgsConstructor(staticName = "getTest2")
    public static class Test2 {

        private String a;
        private String b;
        private String c;

    }

}

使用如下:

    ConstructorBean constructorBean = new ConstructorBean("賀利權", "河北省");
    ConstructorBean.Test1 test1=new ConstructorBean.Test1();
    ConstructorBean.Test2 test2= ConstructorBean.Test2.getTest2();

小結:

即使一個字段被明確初始化 null,Lombok也會考慮避免 null ,並且不會將該字段視爲“必需”參數。假設是,如果你明確地將null一個已經標記爲@NonNull信號的字段賦值,你必須知道你在做什麼。
將@java.beans.ConstructorProperties設計爲永遠不會爲沒有參數的構造函數添加註解。這也解釋了爲什麼@NoArgsConstructor缺少suppressConstructorProperties註釋方法。生成的靜態工廠方法也無法獲得@ConstructorProperties,因爲此註釋只能添加到真實的構造函數中。
@XArgsConstructor也可以用於枚舉定義。生成的構造函數將始終是私有的,因爲非私有構造函數在枚舉中不合法。你不必指定AccessLevel.PRIVATE。
雖然suppressConstructorProperties已標註爲廢棄,所有的Java環境依然提示 @ConstructorPropertie s註釋可用,但是不排除之後會去除。
flagUsage則是當通過產生一個構造配置鍵不觸發@Data,@Value或任何其他Lombok的註釋。
很無奈的是,貌似Lombok不支持設置特定的構造,如有其他小夥伴知道,希望告知~3q!


五、@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog

Log,Android 常用,一般我們封裝爲一些工具類;

Log4j,貌似後臺的東西,剩下完全不曉得,有小夥伴曉得的麼?


看了半天,還是習慣我們Android Log,還有封裝的工具類,哈哈,簡單貼幾個官方例子,有興趣大家自行了解吧~


六、@Data

這個就6的不要不要的了。

@Data是捆綁特徵超級方便的快捷註釋,其包含:@ToString,@EqualsAndHashCode,@Getter/@Setter和@RequiredArgsConstructor融爲一塊。 
@Data可以處理字段的泛型參數。爲了在爲泛型類構造對象時減少樣板,可以使用該staticConstructor參數生成私有構造函數,以及返回新實例的靜態方法。這樣,javac將推斷變量名稱。因此,通過聲明如下:@Data(staticConstructor=”of”) class Foo { private T x;}你可以Foo通過編寫來創建新的實例:Foo.of(5);而不必編寫:new Foo(5);。
實例很easy,只需要爲實體類添加@Data即可。

使用示例圖:


七、@Builder

Builder,和我們大Android中的Builder模式類似,如果在類上添加@Builder,那麼在實例化的時候,你就可以如下一樣愉快的玩耍~

    BuilderBean bean=BuilderBean.builder()
            .name("賀利權")
            .address("河北")
            .iPhone(666).build();

同樣,我們可以通過@Builder.Default去爲我們的字段設置默認,如下:

    @Builder.Default
    @Getter
    private int iPhone = 888;

如果使用過程中不爲此字段屬性賦值,則將輸出:888

八、@Singular

通過使用註釋註釋其中一個參數(如果註釋了一個方法或構造函數@Builder)或字段(如果註釋了一個類@Builder)@Singular,lombok會將該構建器節點視爲一個集合,並生成2個“加法器”方法而不是“ setter’方法。一個將單個元素添加到集合中,另一個將另一個集合的所有元素添加到集合中。將不會生成setter來設置集合(替換已添加的內容)。“清除”方法也會生成。這些’奇異’的建設者是非常複雜的,以保證以下屬性:
調用時build(),生成的集合將是不可變的。
在調用之後調用“加法器”方法或“清除”方法之一build()不會修改任何已生成的對象,並且如果build()以後再次調用,則會生成另一個集合,其中包含創建構建器後創建的所有元素。
生成的集合將被壓縮到最小的可行格式,同時保持高效。
其目前支持的類型如下:


官方例子:


import lombok.Builder;
import lombok.Singular;
import java.util.Set;

@Builder
public class BuilderExample {
  @Builder.Default private long created = System.currentTimeMillis();
  private String name;
  private int age;
  @Singular private Set<String> occupations;
}

九、@Delegate

任何字段或無參數方法都可以註釋,@Delegate讓lombok生成將調用轉發到此字段的委託方法(或調用此方法的結果)。
十、@Value

@Value 在lombok v0.11.4中作爲實驗性特徵被引入。
@Value是不可變的; 所有字段由private和final默認情況下,也不會產生setter方法。這個類本身也是final默認生成的,因爲不可變性不能被強制轉換爲子類。
我只想說,我TMD。。。


十一、@Accessors

@Accessors 在lombok v0.11.0中作爲實驗性功能引入。
配置 Lombok 如何生成並查找 Get 和 Set
附上官方示例:

import lombok.experimental.Accessors;
import lombok.Getter;
import lombok.Setter;

@Accessors(fluent = true)
public class AccessorsExample {
  @Getter @Setter
  private int age = 10;
}

class PrefixExample {
  @Accessors(prefix = "f") @Getter
  private String fName = "Hello, World!";
}

感覺沒啥卵用~


十二、@Wither

@Wither在lombok v0.11.4中作爲實驗性功能被引入。
相當於一個替代者,還是想不到用處,簡單附上官方提供例子:

import lombok.AccessLevel;
import lombok.NonNull;
import lombok.experimental.Wither;

public class WitherExample {
  @Wither private final int age;
  @Wither(AccessLevel.PROTECTED) @NonNull private final String name;

  public WitherExample(String name, int age) {
    if (name == null) throw new NullPointerException();
    this.name = name;
    this.age = age;
  }
}

十三、@SneakyThrows

@SneakyThrows可以用來隱式地拋出檢查異常,而無需在方法的throws子句中實際聲明。當然,這種有爭議的能力應該謹慎使用。
瞅下官方提供的例子:


 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();
  }
}

還是習慣了java~

十四、@val

這個東東不得不說還是很強大的,類似 JS 中的var。

簡單一句話概括:

沒有確切的類型,也就說,你給傳什麼類型就是什麼類型。
有的小夥伴說了,假設我定義一個val a,我一開始傳入1,接下來傳入String類型,也支持?

LZ這裏默默上圖,請看:


那麼,具體又是如何使用的呢?如下:

    val num=1;
    val numStr="一個";
    var userList=new ArrayList<UserBean1>();

是否秒懂?

少寫一個,是一個,哈哈~~~

十五、@UtilityClass

實用程序類是一個只是函數名稱空間的類。它的任何實例都不存在,它的所有成員都是靜態的。例如,java.lang.Math並且java.util.Collections是衆所周知的實用程序類。該註釋自動將註釋類轉換爲一個。
實用程序類不能實例化。通過標記你的類@UtilityClass,lombok會自動生成一個私有構造函數,該異常構造函數拋出一個異常,標記爲錯誤,添加任何顯式的構造函數,並標記該類final。如果班級是內部班級,班級也會被標記static。
工具類的所有成員都會自動標記爲static。
同樣沒啥卵用,而且還是個試驗品,萬一用爽了下架了,憋着多難受。


十六、lombok config files syntax highlighting

一些基礎配置,感覺沒啥個卵用,有興趣個人瞭解吧~
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章