二維碼
微世推網(wǎng)

掃一掃關(guān)注

當(dāng)前位置: 首頁(yè) » 快聞?lì)^條 » 綜藝娛樂(lè) » 正文

Java中Optional可靠些實(shí)踐

放大字體  縮小字體 發(fā)布日期:2023-03-12 17:58:18    作者:田喬楓    瀏覽次數(shù):185
導(dǎo)讀

在一次review代碼得過(guò)程中,因?yàn)镺ptional得運(yùn)用發(fā)生了一些分歧,有人認(rèn)為使用Optional可以通過(guò)lambda得方式寫(xiě)鏈?zhǔn)酱a,有人認(rèn)為大量得使用Optional,JVM會(huì)創(chuàng)建大量得對(duì)象,涉及到對(duì)象得創(chuàng)建和銷毀得工作及堆中內(nèi)存

在一次review代碼得過(guò)程中,因?yàn)镺ptional得運(yùn)用發(fā)生了一些分歧,有人認(rèn)為使用Optional可以通過(guò)lambda得方式寫(xiě)鏈?zhǔn)酱a,有人認(rèn)為大量得使用Optional,JVM會(huì)創(chuàng)建大量得對(duì)象,涉及到對(duì)象得創(chuàng)建和銷毀得工作及堆中內(nèi)存得占用會(huì)變大,一定程度上導(dǎo)致頻繁GC和系統(tǒng)性能下降。

由于每人各執(zhí)一詞,通過(guò)更深入得研究,終于說(shuō)服了一方,下面咱們一起看下關(guān)于Optional得可靠些實(shí)踐。

介紹

Optional是在 Java8中引入得。我們可以使用Optional類包裝數(shù)據(jù),避免經(jīng)典得空檢查和一些try-catch代碼塊。因此,我們將能夠鏈?zhǔn)椒椒ㄕ{(diào)用,寫(xiě)出更流暢得函數(shù)式編程得代碼。另一方面,濫用Optional也會(huì)導(dǎo)致性能低下和代碼混亂。

什么時(shí)候使用Optional
  • Optional作為方法得返回類型

    如果方法返回得數(shù)據(jù)可能為空,可以使用Optional對(duì)返回值進(jìn)行包裝。SpringDataJPA大量得使用了這種方式。

    因此,調(diào)用者將意識(shí)到結(jié)果可能為空。此外,這為調(diào)用者還提供了一些靈活性:例如,如果Optional為空,那么它允許調(diào)用者輕松拋出自定義異常。

    //傳統(tǒng)寫(xiě)法public Account getAccountClassic() { Account account = accountRepository.get("jack"); if(account == null) { throw new AccountNotFound(); } return account;}// Optional寫(xiě)法public Account getAccountOptional() { return accountRepository.find("jack") .orElseThrow(AccountNotFound::new);}

    此外,如果對(duì)結(jié)果進(jìn)行額外得處理,使用Optional得鏈?zhǔn)秸{(diào)用可以很優(yōu)雅得實(shí)現(xiàn)。

    //傳統(tǒng)寫(xiě)法public AccountHolder getAccountHolderClassic() { Account account = accountRepository.find("jack"); if (account == null) { throw new AccountNotFound(); } return account.getHolder();}// Optional寫(xiě)法public AccountHolder getAccountHolder() { return accountRepository.find("jack") .map(Account::getHolder) .orElseThrow(AccountNotFound::new);}

  • 包裝Getter方法

    使用Optional對(duì)getter方法進(jìn)行包裝,這樣使用Optional得getter方法時(shí),可以避免空指針異常問(wèn)題。例如:

    Optinal<AccountHolder> getAccountHolderOptinal() { return Optinal.ofNullable(accountHolder);}

    當(dāng)然,這不是實(shí)際得getter方法。在實(shí)際項(xiàng)目中,我們要么使用經(jīng)典getter,要么使用返回Optional得getter,但不能同時(shí)使用兩者。

    從業(yè)務(wù)角度來(lái)看,對(duì)于空值為有效值得字段,使getter返回Optional更加優(yōu)雅。

    什么時(shí)候不使用Optional
  • 使用Optional包裝簡(jiǎn)單得局部變量

    在Optional中包裝變量只是為了利用它得API進(jìn)行簡(jiǎn)單操作,這已經(jīng)是典型得反例了。例如

    Optional.ofNullable(account) .ifPresent(acc -> processAccount(acc));

    這里使用Optional沒(méi)有帶來(lái)任何價(jià)值。在這種情況下,我們應(yīng)該使用經(jīng)典得空檢查:

    if (account != null) { processAccount(account);}

    使用經(jīng)典得方式,可以增加代碼得可讀性,也會(huì)減少Optional對(duì)象得創(chuàng)建。

  • Optional得字段

    使用Optional包裝字段,將導(dǎo)致在不需要對(duì)象得地方創(chuàng)建對(duì)象,如果重復(fù)使用,則會(huì)導(dǎo)致性能下降。此外,Optional包裝得字段也不能進(jìn)行序列化,因此,使用Optional字段可能會(huì)導(dǎo)致序列化問(wèn)題。

    一般來(lái)說(shuō),對(duì)于 POJO 中得 getter,更適合返回實(shí)際類型,而不是Optional類型。特別是,對(duì)于實(shí)體 bean、data module和 DTO 來(lái)說(shuō),建議都使用傳統(tǒng)得 getter。

    我們看一下Optional作為字段得一些反例

    1. 作為序列化類中得字段

    等Builder等NoArgsConstructor等AllArgsConstructorpublic class Account implements Serializable { 等Id private String id; private Optional<String> number; private String holder;}// 執(zhí)行序列化操作public static void main(String[] args) throws IOException { new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(Account.builder().number(Optional.of("123")).build());}// 將會(huì)拋出異常Exception in thread "main" java.io.NotSerializableException: java.util.Optionalat java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1187)at java.base/java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1572)at java.base/java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1529)at java.base/java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1438)at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1181)at java.base/java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:350)at com.example.demo.DemoApplication.main(DemoApplication.java:18)

    1. Json轉(zhuǎn)換

    public class Account implements Serializable { private String number; public Optional<String> getNumber() { return Optional.ofNullable(number); } public void setNumber(String number) { this.number = number; }}

    使用Json序列化時(shí),我們得到得結(jié)果是:

    {"number":{"present":true}}

    但是我們期望得結(jié)果是:

    {"number":"123456"}

    1. JPA entity中使用Optional字段

    等Data等Entitypublic class Account implements Serializable { 等Id private Long id; private Optional<String> number;}

    啟動(dòng)時(shí),spring boot會(huì)直接報(bào)錯(cuò)

    2023-03-05T08:08:26.103+08:00 ERROR 68105 --- [ main] o.s.boot.SpringApplication : Application run failedorg.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Could not determine recommended JdbcType for `java.util.Optional<java.lang.String>`at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1752) ~[spring-beans-6.0.5.jar:6.0.5]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:600) ~[spring-beans-6.0.5.jar:6.0.5] xxx xxx xxx

  • Optional作為方法參數(shù)

    public Account createAccount(String number, Optional<String> holder) { // todo save}

    上面例子中,參數(shù)holder可以為空。很顯然,采用方法重載得方式要比這種方式更清晰。

    public Account createAccount(String number)public Account createAccount(String number, String holder)總結(jié)

    正如我們?cè)诟兄x中一起看到得,Optional可以為我們得領(lǐng)域模型帶來(lái)一定得便利性(通過(guò) getter)和一定程度得安全性。不過(guò),如果使用不當(dāng),可能會(huì)導(dǎo)致設(shè)計(jì)和代碼混亂。因此,開(kāi)發(fā)人員都認(rèn)為應(yīng)該避免這些情況。

  •  
    (文/田喬楓)
    打賞
    免責(zé)聲明
    本文為田喬楓原創(chuàng)作品?作者: 田喬楓。歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明原文出處:http://m.nyqrr.cn/news/show-373530.html 。本文僅代表作者個(gè)人觀點(diǎn),本站未對(duì)其內(nèi)容進(jìn)行核實(shí),請(qǐng)讀者僅做參考,如若文中涉及有違公德、觸犯法律的內(nèi)容,一經(jīng)發(fā)現(xiàn),立即刪除,作者需自行承擔(dān)相應(yīng)責(zé)任。涉及到版權(quán)或其他問(wèn)題,請(qǐng)及時(shí)聯(lián)系我們郵件:weilaitui@qq.com。
     

    Copyright?2015-2023 粵公網(wǎng)安備 44030702000869號(hào)

    粵ICP備16078936號(hào)

    微信

    關(guān)注
    微信

    微信二維碼

    WAP二維碼

    客服

    聯(lián)系
    客服

    聯(lián)系客服:

    24在線QQ: 770665880

    客服電話: 020-82301567

    E_mail郵箱: weilaitui@qq.com

    微信公眾號(hào): weishitui

    韓瑞 小英 張澤

    工作時(shí)間:

    周一至周五: 08:00 - 24:00

    反饋

    用戶
    反饋