成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

使用Optional擺脫NPE的折磨

BDEEFE / 783人閱讀

摘要:在目前的工作中,我對(duì)中的和表達(dá)式都使用得很多,之前也寫(xiě)了兩篇文章來(lái)總結(jié)對(duì)應(yīng)的知識(shí)。為了避免,他們會(huì)加很多判斷語(yǔ)句,使得代碼的可讀性變得很差。在后面的開(kāi)發(fā)中,可以使用設(shè)計(jì),這樣可以設(shè)計(jì)出更安全的接口和方法。

在目前的工作中,我對(duì)Java中的Stream和Lambda表達(dá)式都使用得很多,之前也寫(xiě)了兩篇文章來(lái)總結(jié)對(duì)應(yīng)的知識(shí)。

024:Java流實(shí)現(xiàn)Shell:cat 1.log | grep a | sort | uniq -c | sort -rn

函數(shù)式編程讓你忘記設(shè)計(jì)模式

不過(guò)對(duì)于Optional這個(gè)特性,一直沒(méi)有很好地使用起來(lái),所以最近又開(kāi)始閱讀《Java 8實(shí)戰(zhàn)》這本書(shū),本文是針對(duì)其中第10章的一個(gè)學(xué)習(xí)總結(jié)。

背景

在Java中,如果你嘗試對(duì)null做函數(shù)調(diào)用,就會(huì)引發(fā)NullPointerException(NPE),NPE是Java程序開(kāi)發(fā)中的最典型的異常,對(duì)于Java開(kāi)發(fā)者來(lái)說(shuō),無(wú)論你是初出茅廬的新人和還工作多年的老司機(jī),NPE經(jīng)常讓他們翻車(chē)。為了避免NPE,他們會(huì)加很多if判斷語(yǔ)句,使得代碼的可讀性變得很差。

從軟件設(shè)計(jì)的角度來(lái)看,null本身是沒(méi)有意義的語(yǔ)義,這是一種對(duì)缺失變量值的錯(cuò)誤的建模。

從Java類型系統(tǒng)的角度看,null可以被賦值給任何類型的變量,并且不斷被傳遞,知道最后誰(shuí)也不知道它是從哪里引入的。

Optional的引入

Java設(shè)計(jì)者從Haskell和Scala中獲取靈感,在Java 8中引入了一個(gè)新的類java.util.Optional。如果一個(gè)接口返回Optional,可以表示一個(gè)人可能有車(chē)也可能沒(méi)有車(chē),這個(gè)比簡(jiǎn)單的返回Car要更明確,閱讀代碼的人不需要提前準(zhǔn)備業(yè)務(wù)知識(shí)。

Optional的目的就在于此:通過(guò)類型系統(tǒng)讓你的領(lǐng)域模型中隱藏的知識(shí)顯式地體現(xiàn)在你的代碼中。

Optional的使用
方法 描述
empty 返回一個(gè)空的Optional實(shí)例
filter 如果值存在并且滿足提供的過(guò)濾條件,則返回包含該值的Optional對(duì)象;否則就返回一個(gè)空的Optional對(duì)象
map 如果值存在,就對(duì)該值執(zhí)行提供的mapping函數(shù)調(diào)用
flatMap 如果值存在,就對(duì)該值執(zhí)行提供的mapping函數(shù)調(diào)用,返回一個(gè)Optional類型的值,否則就返回一個(gè)空的Optional對(duì)象
ifPresent 如果值存在,就執(zhí)行使用該值的方法調(diào)用,否則什么也不做
of 將指定值用Optional封裝之后返回,如果該值為null,則拋出一個(gè)NPE
ofNullable 將指定值用Optional封裝之后返回,如果該值為null,則返回一個(gè)空的Optional對(duì)象
orElse 如果有值則返回,否則返回一個(gè)默認(rèn)值
orElseGet 如果有值則返回,否則返回一個(gè)由指定的Supplier接口生成的值(如果默認(rèn)值的生成代價(jià)比較高的話,則適合使用orElseGet方法)
orElseThrow 如果有值則返回,否則返回一個(gè)由指定的Supplier接口拋出的異常
get 如果值存在,則返回該值,否則拋出一個(gè)NoSuchElementException異常
isPresent 如果值存在則返回true,否則返回false

上面這張表里列舉了Optional的基礎(chǔ)API,我這里列舉了一些使用的tips:

你可以用ofNullable將一個(gè)可能為null的對(duì)象封裝為Optional對(duì)象,然后獲取值的時(shí)候使用orElse方法提供默認(rèn)值;可以使用empty方法創(chuàng)建一個(gè)空的Optional對(duì)象;of方法一般不用,不過(guò)如果你知道某個(gè)值不可能為null,則可以用Optional封裝該值,這樣它一旦為null就會(huì)拋出異常。

//empty方法的使用
Optional optCar = Optional.empty();

//of方法的使用
Optional optCar = Optional.of(car);

//ofNullable方法的使用
Optional optCar = Optional.ofNullable(car);

你可以使用map方法從Optional對(duì)象中它封裝的值中的某個(gè)字段的值;

Optional optInsurance = Optional.ofNullable(insurance);
Optional name = optInsurance.map(Insurance::getName); 

如果需要連續(xù)、層層遞進(jìn)的從某個(gè)對(duì)象鏈的末端獲取字段的值,則不能全部使用map方法,需要先使用flatMap,最后再使用map方法;

//轉(zhuǎn)換之前
public String getCarInsuranceName(Person person) {
  return person.getCar().getInsurance().getName();
}

//轉(zhuǎn)換后
public String getCarInsuranceName(Optional person) {
  return person.flatMap(Person::getCar)
               .flatMap(Car::Insurance)
               .map(Insurance::getName)
               .orElse("Unknown");
}

Optional中的map、flatMap和filter方法,在概念是與Stream中對(duì)應(yīng)的方法都很類似,區(qū)別就在于Optional中的元素至多有一個(gè),算是Stream的一種特殊情況——一種特殊的集合。

不要使用ifPresent和get方法,它們本質(zhì)上和不適用Optional對(duì)象之前的模式相同,都是臃腫的if-then-else判斷語(yǔ)句;

由于Optional無(wú)法序列化,所以在領(lǐng)域模型中,無(wú)法將某個(gè)字段定義為Optional的,原因是:Optional的設(shè)計(jì)初衷僅僅是要支持能返回Optional對(duì)象的語(yǔ)法,如果我們希望在域模型中引入Optional,則可以用下面這種替代的方法:

public class Person {
  private Car car;
  public Optional getCarAsOptional() {
    return Optional.ofNullable(car);
  }
}

不要使用基礎(chǔ)類型的Optional對(duì)象,原因是:基礎(chǔ)類型的Optional對(duì)象不支持map、flatMap和filter方法,而這些方法是Optional中非常強(qiáng)大的方法。

實(shí)戰(zhàn)案例 案例1:使用工具類方法改良可能拋出異常的API

Java方法處理異常結(jié)果的方式有兩種:返回null(或錯(cuò)誤碼);拋出異常,例如:Integer.parseInt(String)這個(gè)方法——如果無(wú)法解析到對(duì)應(yīng)的整型,該方法就拋出一個(gè)NumberFormationException,這種情況下我們一般會(huì)使用try/catch語(yǔ)句處理異常情況。

一般我們建議將try/catch塊多帶帶提取到一個(gè)方法中,在這里使用Optional設(shè)計(jì)這個(gè)方法,代碼如下。在開(kāi)發(fā)中,可以嘗試構(gòu)建一個(gè)OptionalUtility工具類,將這些復(fù)雜的try/catch邏輯封裝起來(lái)。

public static Optional stringToInt(String a) {
  try{
    return Optional.of(Integer.parseInt(s));
  } catch  (NumberFormationException e) {
    return Optional.empty();
  }
}
案例2:綜合案例

現(xiàn)在有個(gè)方法,是嘗試從一個(gè)屬性映射中獲取某個(gè)關(guān)鍵詞對(duì)應(yīng)的值,例子代碼如下:

   public static int readDuration(Properties properties, String name) {
        String value = properties.getProperty(name);
        if (value != null) {
            try {
                int i = Integer.parseInt(value);
                if (i > 0) {
                    return i;
                }
            } catch (NumberFormatException e) {

            }
        }
        return 0;
    }

使用Optional的寫(xiě)法后,代碼如下所示:

    public static int readDurationWithOptional(Properties properties, String name) {
        return Optional.ofNullable(properties.getProperty(name))
            .flatMap(OptionalUtility::stringToInt)
            .filter(integer -> integer > 0)
            .orElse(0);
    }

如果需要訪問(wèn)的屬性值不存在,Properites.getProperty(String)方法的返回值就是一個(gè)null,使用noNullable工廠方法就可以將該值轉(zhuǎn)換為Optional對(duì)象;接下來(lái),可以使用flatMap將一個(gè)Optional轉(zhuǎn)換為Optional對(duì)象;最后使用filter過(guò)濾掉負(fù)數(shù),然后就可以使用orElse獲取屬性值,如果拿不到則返回默認(rèn)值0。

總結(jié)

使用Optional的思路和Stream相同,都是鏈?zhǔn)剿悸?,跟?shù)據(jù)庫(kù)查詢似的,表達(dá)力很強(qiáng),而且省去了哪些復(fù)雜的try/catch和if-then-else方法。在后面的開(kāi)發(fā)中,可以使用Optional設(shè)計(jì)API,這樣可以設(shè)計(jì)出更安全的接口和方法。

本號(hào)專注于后端技術(shù)、JVM問(wèn)題排查和優(yōu)化、Java面試題、個(gè)人成長(zhǎng)和自我管理等主題,為讀者提供一線開(kāi)發(fā)者的工作和成長(zhǎng)經(jīng)驗(yàn),期待你能在這里有所收獲。

本號(hào)專注于后端技術(shù)、JVM問(wèn)題排查和優(yōu)化、Java面試題、個(gè)人成長(zhǎng)和自我管理等主題,為讀者提供一線開(kāi)發(fā)者的工作和成長(zhǎng)經(jīng)驗(yàn),期待你能在這里有所收獲。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/75392.html

相關(guān)文章

  • 通過(guò)JDK 8避免NPE,可選

    摘要:從開(kāi)始,您可以通過(guò)返回來(lái)避免。例如,此方法返回一個(gè)空的,而不是返回可選獲取指定的卡片內(nèi)容的代碼從JDK 8開(kāi)始,您可以通過(guò)返回Optional來(lái)避免NullPointerException。 例如,此方法返回一個(gè)空的Optional:,而不是返回null public可選fetchShoppingCart(long id){ ???? ShoppingCart cart = //獲取...

    lavor 評(píng)論0 收藏0
  • Java8實(shí)用技能

    大概一年多之前,我對(duì)java8的理解還僅限一些只言片語(yǔ)的文章之上,后來(lái)出于對(duì)函數(shù)式編程的興趣,買(mǎi)了本參考書(shū)看了一遍,然后放在了書(shū)架上,后來(lái),當(dāng)我接手大客戶應(yīng)用的開(kāi)發(fā)工作之后,java8的一些工具,對(duì)我的效率有了不小的提升,因此想記錄一下java8的一些常用場(chǎng)景,我希望這會(huì)成為一個(gè)小字典,能讓我免于頻繁翻書(shū),但是總能找到自己想找的知識(shí)。 用于舉例的model: @Data public class ...

    microcosm1994 評(píng)論0 收藏0
  • 給女朋友講解什么是Optional【JDK 8特性】

    摘要:接口例子如果容器的對(duì)象存在,則對(duì)其執(zhí)行調(diào)用函數(shù)得到返回值。上面一句代碼對(duì)應(yīng)著最開(kāi)始的老寫(xiě)法方法直接看源碼方法與方法類似,區(qū)別在于函數(shù)的返回值不同。 前言 只有光頭才能變強(qiáng) 前兩天帶女朋友去圖書(shū)館了,隨手就給她來(lái)了一本《與孩子一起學(xué)編程》的書(shū),于是今天就給女朋友講解一下什么是Optional類。 至于她能不能看懂,那肯定是看不懂的。(學(xué)到變量/for循環(huán)的女人怎么能看懂呢) 不知道大家還...

    caspar 評(píng)論0 收藏0
  • 【修煉內(nèi)功】[Java8] 使用Optional正確姿勢(shì)及序列化問(wèn)題

    摘要:本文已收錄修煉內(nèi)功躍遷之路的為解決空的問(wèn)題帶來(lái)了很多新思路,查看源碼,實(shí)現(xiàn)非常簡(jiǎn)單,邏輯也并不復(fù)雜。 本文已收錄【修煉內(nèi)功】躍遷之路 showImg(https://segmentfault.com/img/bVbrCvp?w=852&h=480); Java8的Optional為解決空的問(wèn)題帶來(lái)了很多新思路,查看Optional源碼,實(shí)現(xiàn)非常簡(jiǎn)單,邏輯也并不復(fù)雜。Stuart Ma...

    Ajian 評(píng)論0 收藏0
  • Java8新特性總覽

    摘要:新特性總覽標(biāo)簽本文主要介紹的新特性,包括表達(dá)式方法引用流默認(rèn)方法組合式異步編程新的時(shí)間,等等各個(gè)方面。還有對(duì)應(yīng)的和類型的函數(shù)連接字符串廣義的歸約匯總起始值,映射方法,二元結(jié)合二元結(jié)合。使用并行流時(shí)要注意避免共享可變狀態(tài)。 Java8新特性總覽 標(biāo)簽: java [TOC] 本文主要介紹 Java 8 的新特性,包括 Lambda 表達(dá)式、方法引用、流(Stream API)、默認(rèn)方...

    mayaohua 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<