使用lombok編寫優(yōu)雅的Bean對(duì)象-創(chuàng)新互聯(lián)

使用java編寫代碼,十之八九都是在寫java類,從而構(gòu)建java對(duì)象。lombok之前也說了不少,但使用了這么多年,感覺還是有很多技巧可以使用的。

成都創(chuàng)新互聯(lián)堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站制作、成都做網(wǎng)站、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的沈北新網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

毫無疑問,使用lombok,編寫的java代碼很優(yōu)雅,而使用起來和普通的java編碼方式創(chuàng)建的類毫無二致。

不過,這樣就滿足了嗎?實(shí)際上lombok很多注解,讓這個(gè)java類在使用的時(shí)候,也可以更優(yōu)雅。

本文就從ORM實(shí)體類、Builder模式工具類、Wither工具類以及Accessors工具類幾個(gè)層面對(duì)比一下。

首先說明,不同的方式本質(zhì)上沒有優(yōu)劣之分,不過在不同的應(yīng)用場(chǎng)景就會(huì)變得很奇妙了。

ORM實(shí)體類
當(dāng)一個(gè)java Bean類作為ORM實(shí)體類,或者xml、json的映射類時(shí),需要這個(gè)類有這幾個(gè)特征:

擁有無參構(gòu)造器
擁有setter方法,用以反序列化;
擁有g(shù)etter方法,用以序列化。
那么最簡(jiǎn)單的情況就是:

@Data
public class UserBean{
  private Integer id;
  private String userName;
}

復(fù)習(xí)一下,Data 注解相當(dāng)于裝配了 @Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode
那么,作為實(shí)體類、或者序列化的Bean類,足夠用了。

Builder
構(gòu)造器模式,在很多工具類中頻繁的使用。

package com.pollyduan.builder;

import lombok.Builder;

@Builder
public class UserBean {
      private Integer id;
      private String userName;
}

它做了什么事?

它創(chuàng)建了一個(gè)private 的全參構(gòu)造器。也就意味著 無參構(gòu)造器沒有; 同時(shí)也意味著這個(gè)類不可以直接構(gòu)造對(duì)象。
它為每一個(gè)屬性創(chuàng)建了一個(gè)同名的方法用于賦值,代替了setter,而該方法的返回值為對(duì)象本身。
使用一下:

UserBean u=UserBean.builder()
    .id(1001)
    .userName("polly")
    .build();
System.out.println(u);

還不錯(cuò),然并卵,由于這個(gè)Bean并沒有g(shù)etter方法,里邊的數(shù)據(jù)沒辦法直接使用。光說沒用,繼續(xù)執(zhí)行你會(huì)發(fā)現(xiàn)輸出是這個(gè)東西:com.pollyduan.builder.UserBean@20322d26,連看都看不出是什么東東。因此,Builder提供了一個(gè)種可能性,實(shí)際使用還需要更多的東西。

那么,我們?yōu)榱藴y(cè)試方便需要添加 @ToString() 注解,就會(huì)輸出 UserBean(id=1001, userName=polly)

換一個(gè)思路,你可能想,我不添加ToString注解,我把他轉(zhuǎn)成json輸出:

UserBean u=UserBean.builder()
    .id(1001)
    .userName("polly")
    .build();
ObjectMapper mapper=new ObjectMapper();
System.out.println(mapper.writeValueAsString(u));

很不幸,你會(huì)收到下面的異常:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class com.pollyduan.builder.UserBean and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)

看到 no properties discovered 了吧,沒錯(cuò),工具類無法找到屬性,因?yàn)闆]有 getter,那么我們加上 @Getter 就可以了。

package com.pollyduan.builder;

import lombok.Builder;
import lombok.Getter;

@Builder
@Getter
public class UserBean {
      private Integer id;
      private String userName;
}

序列化為json可以了,那么從一個(gè)json反序列化為對(duì)象呢?

@Builder
@Getter
@Setter
public class UserBean {
      private Integer id;
      private String userName;
}

還是不行,如無意外,會(huì)遇到 com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance ofcom.pollyduan.builder.UserBean(no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

前面已經(jīng)交代了,光增加 @Setter 還不夠,他還需要一個(gè)無參構(gòu)造器。那么,下面可以嗎?

package com.pollyduan.builder;

import lombok.Builder;
import lombok.Data;

@Builder
@Data
public class UserBean {
      private Integer id;
      private String userName;
}

同樣不行,因?yàn)殡m然 Data使用的時(shí)候可以直接使用無參構(gòu)造器,但由于 Builder 引入了全參構(gòu)造器,那么按照java原生的規(guī)則,無參構(gòu)造器就沒有了。那么就再加一個(gè)無參構(gòu)造器

@Builder
@Data
@NoArgsConstructor

很不幸,Builder又報(bào)錯(cuò)了,它找不到全參構(gòu)造器了。好吧,最終的效果如下:

@Builder
@Data
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor

注意全參構(gòu)造器的訪問級(jí)別,不要破壞Builder的規(guī)則。
更進(jìn)一步,看如下示例:

package com.pollyduan.builder;

import java.util.List;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Builder
@Data
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor
public class UserBean {
      private Integer id;
      private String userName;
      private List<String> addresses;
}

思考一下,這個(gè)List 我們也需要在外面new 一個(gè) ArrayList,然后build進(jìn)去,使用起來并不舒服。lombok提供了另一個(gè)注解配合使用,那就是 @Singular,如下:

package com.pollyduan.builder;

import java.util.List;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Builder
@Data
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor
public class UserBean {
      private Integer id;
      private String userName;
      @Singular
      private List<String> favorites;
}

那么就可以這樣操作這個(gè)列表了。

UserBean u = UserBean.builder()
    .id(1001)
    .userName("polly")
    .favorite("music")
    .favorite("movie")
    .build();

是不是很方便?同時(shí)還提供了一個(gè) clearXXX方法,清空集合。

還有一個(gè)小坑,如果我們?cè)黾右粋€(gè)example屬性,然后給它一個(gè)默認(rèn)值:

@Builder
@Data
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor
public class UserBean {
      private Integer id;
      private String userName;
      private String example="123456";
}

測(cè)試一下看:

UserBean u = UserBean.builder()
    .id(1001)
    .userName("polly")
    .build();
System.out.println(u.toString());

輸出結(jié)果:UserBean(id=1001, userName=polly, example=null)

咦,不對(duì)呀?缺省值呢??這要從Builder的原理來解釋,他實(shí)際上是分別設(shè)置了一套屬性列表的值,然后使用全參構(gòu)造器創(chuàng)建對(duì)象。那么,默認(rèn)值在Bean上,不在Builder上,那么Builder沒賦值,它的值就是null,最后把所有屬性都復(fù)制給UserBean,從而null覆蓋了默認(rèn)值。

如何讓Builder實(shí)體來有默認(rèn)值呢?只需要給該字段增加 @Default 注解級(jí)可。

package com.pollyduan.builder;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Builder.Default;
import lombok.Data;
import lombok.NoArgsConstructor;

@Builder
@Data
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor
public class UserBean {
      private Integer id;
      private String userName;
      @Default
      private String example="123456";
}

重新執(zhí)行測(cè)試用例,輸出:UserBean(id=1001, userName=polly, example=123456),OK,沒毛病了。

Wither
用wither方式構(gòu)建對(duì)象,這在Objective-C 中比較多見。

適用的場(chǎng)景是,使用幾個(gè)必要的參數(shù)構(gòu)建對(duì)象,其他參數(shù),動(dòng)態(tài)的拼裝。舉個(gè)例子,我們構(gòu)建一個(gè)ApiClient,它的用戶名和密碼是必須的,他的ApiService的地址有一個(gè)默認(rèn)值,然后我們可以自己定制這個(gè)地址。

package com.pollyduan.wither;

import lombok.AllArgsConstructor;
import lombok.experimental.Wither;

@Wither
@AllArgsConstructor //WITHER NEED IT.
public class ApiClient {
    private String appId;
    private String appKey;
    private String endpoint="http://api.pollyduan.com/myservice";
}

如何使用呢?

@Test
public void test1() {
    ApiClient client1=new ApiClient(null, null,null);
    System.out.println(client1);

    Object client2 = client1.withAppId("10001")
        .withAppKey("abcdefg")
        .withEndpoint("http://127.0.0.1/");
    System.out.println(client2);
}

默認(rèn)的使用null去初始化一個(gè)對(duì)象還是很奇怪的。和 Builder一樣,Wither也是提供了可能性,實(shí)際使用還需要調(diào)整一下。

我們可以設(shè)置一個(gè)必選參數(shù)的構(gòu)造器,如下:

package com.pollyduan.wither;

import lombok.AllArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.experimental.Wither;

@RequiredArgsConstructor
@Wither
@AllArgsConstructor
public class ApiClient {
    @NonNull
    private String appId;
    @NonNull
    private String appKey;
    private String endpoint="http://api.pollyduan.com/myservice";
}

這樣使用時(shí)就可以這樣:

@Test
    public void test1() {
        ApiClient client1=new ApiClient("10001", "abcdefgh");
        System.out.println(client1);

        Object client2 = client1.withEndpoint("http://127.0.0.1/");
        System.out.println(client2);
    }

是不是優(yōu)雅了很多?而且實(shí)際上使用時(shí)也使用鏈?zhǔn)秸Z法:

ApiClient client1=new ApiClient("10001", "abcdefgh")
   withEndpoint("http://127.0.0.1/");

另外還有一個(gè)小細(xì)節(jié),前面的示例輸出如下:

com.pollyduan.wither.ApiClient@782830e
com.pollyduan.wither.ApiClient@470e2030

這個(gè)日志表明,with() 返回的對(duì)象并不是原來的對(duì)象,而是一個(gè)新對(duì)象,這很重要。

Accessors
訪問器模式,是給一個(gè)普通的Bean增加一個(gè)便捷的訪問器,包括讀和寫。

它有兩種工作模式,fluent和chain,舉例說明:

package com.pollyduan.accessors;

import lombok.Data;
import lombok.experimental.Accessors;

@Accessors(fluent = true)
@Data
public class UserBean {
    private Integer id;
    private String userName;
    private String password;

}

使用代碼:

UserBean u=new UserBean()
    .id(10001)
    .userName("polly")
    .password("123456");

u.userName("Tom");
System.out.println(u.userName());

這和 Builder 類似,但更小巧,而且不影響屬性的讀寫,只不過使用屬性同名字符串代替了getter和setter。

另一個(gè)模式是 chain:

UserBean u=new UserBean()
    .setId(10001)
    .setUserName("polly")
    .setPassword("123456");

u.setUserName("Tom");
System.out.println(u.getUserName());

可以看得出來,這fluent的區(qū)別就在于使用getter和setter。

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。

本文標(biāo)題:使用lombok編寫優(yōu)雅的Bean對(duì)象-創(chuàng)新互聯(lián)
當(dāng)前網(wǎng)址:http://bm7419.com/article46/ddhoeg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供Google面包屑導(dǎo)航、外貿(mào)建站、微信小程序軟件開發(fā)、網(wǎng)站內(nèi)鏈

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化