Optional類的學(xué)習(xí)和使用

一祝懂、Optional簡(jiǎn)介


NPE(NullPointerException)是Java應(yīng)用程序中常見(jiàn)的異常。過(guò)去,為了解決空指針異常蚊丐,Google公司著名的Guava項(xiàng)目引入了Optional類飘蚯,Guava通過(guò)使用檢查空值的方式來(lái)防止代碼污染馍迄,它鼓勵(lì)程序員寫(xiě)更干凈的代碼福也。如今,受到Google Guava的啟發(fā)攀圈,Java 8引入了一個(gè)同名的Optional類暴凑,可以用它來(lái)封裝可能為空的引用,但它絕不是終結(jié)空指針赘来,更多的是提醒你需要關(guān)注null的情況现喳,Optional類提供很多有用的方法,這樣我們就不用顯式進(jìn)行空值檢測(cè)犬辰。

Optional:按照字面英文解釋為“可選的” 意思嗦篱,但此處的語(yǔ)義是指某個(gè)值可能有也可能沒(méi)有(null)

Optional 被定義為一個(gè)簡(jiǎn)單的容器幌缝,它可以保存類型T的值,其值可能是null或者不是null灸促。在Java 8之前一般某個(gè)函數(shù)應(yīng)該返回非空對(duì)象但是偶爾卻可能返回了null,而在Java 8 以后涵卵,不推薦你返回null而是返回Optional浴栽。

Optional官方文檔地址:http://docs.oracle.com/javase/8/docs/api/java/util/Optional.html

二、Optional的方法及使用


private static final Optional<?> EMPTY = new Optional<>();
private final T value;

2.1轿偎、構(gòu)造函數(shù)

  • private Optional():構(gòu)建一個(gè)空的 Optional 實(shí)例典鸡。實(shí)例中的 value == null
private Optional() {
        this.value = null;
    }
  • private Optional(T var1):構(gòu)建一個(gè)Optional 實(shí)例。實(shí)例中的 value == var1坏晦。var1為NULL會(huì)拋NPE
private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

2.2萝玷、獲取 Optional 實(shí)例方法

  • public static<T> Optional<T> empty():返回空的 Optional 實(shí)例
public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }
  • public static <T> Optional<T> of(T value):返回一個(gè)指定非null值的Optional
public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }
  • public static <T> Optional<T> ofNullable(T value):如果value值非空,返回 Optional 描述的指定值英遭,否則返回空的 Optional
public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

示例代碼:

      // 創(chuàng)建一個(gè)值為空的Optional對(duì)象
      Optional<Object> emptyOptional = Optional.empty();

      // 創(chuàng)建一個(gè)值非空的Optional對(duì)象
      Optional<String> ofOptional = Optional.of("optional");

      // 創(chuàng)建一個(gè)值允許為空的Optional對(duì)象
      Optional<Object> ofNullableOptional = Optional.ofNullable(null);

2.3间护、獲取 Optional 實(shí)例中的 value

  • public T get():如果在這個(gè)Optional中包含這個(gè)值,返回值挖诸,否則拋出異常:NoSuchElementException
public T get() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }
  • public T orElse(T other):如果存在該值汁尺,返回值, 否則返回 other
public T orElse(T other) {
        return value != null ? value : other;
    }
  • public T orElseGet(Supplier<? extends T> other):如果存在該值多律,返回值痴突, 否則觸發(fā) other,并返回 other 調(diào)用的結(jié)果
public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }
  • public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) :如果存在該值狼荞,返回包含的值辽装,否則拋出由 Supplier 繼承的異常
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }

示例代碼:

     // get() 如果在這個(gè)Optional中包含這個(gè)值,返回值,否則拋出異常:NoSuchElementException
     System.out.println("optional get value:" + Optional.of("getValue").get());

     try {
         // 在空的Optional實(shí)例上調(diào)用get()相味,拋出NoSuchElementException
         System.out.println(Optional.empty().get());
     }catch (NoSuchElementException e){
         System.out.println(e.getMessage());
     }

     // orElse() 如果存在該值拾积,返回值,否則返回 other
     System.out.println("empty Optional orElse value:" + Optional.empty().orElse("orElseValue"));
     System.out.println("full Optional orElse value:" + Optional.of("optional").orElse("orElseValue"));

     // orElseGet() 如果存在該值,返回值,否則觸發(fā) other,并返回 other 調(diào)用的結(jié)果
     System.out.println("empty Optional orElseGet value:" + Optional.ofNullable(null).orElseGet(() -> "orElseGetValue"));
     System.out.println("full Optional orElseGet value:" + Optional.of("fullValue").orElseGet(() -> "orElseGetValue"));

     // orElseThrow() 如果存在該值,返回包含的值,否則拋出異常
     System.out.println("Optional orElseThrow value:" + Optional.of("optional").orElseThrow(() -> new RuntimeException("Unknown")));
     try {
         // orElseThrow會(huì)拋出lambda表達(dá)式或方法生成的異常
         Optional.empty().orElseThrow(() -> new RuntimeException("Unknown"));
     }catch (RuntimeException e){
         System.out.println(e.getMessage());
     }

運(yùn)行結(jié)果:

optional get value:getValue
No value present
empty Optional orElse value:orElseValue
full Optional orElse value:optional
empty Optional orElseGet value:orElseGetValue
full Optional orElseGet value:fullValue
Optional orElseThrow value:optional
Unknown

2.4、判斷 Optional 是否存在

  • public boolean isPresent():如果值存在則方法會(huì)返回true,否則返回 false
public boolean isPresent() {
        return value != null;
    }
  • public void ifPresent(Consumer<? super T> consumer):如果值存在則使用該值調(diào)用 consumer 拓巧,否則不做任何事情
public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }

示例代碼:

    // 判斷Optional對(duì)象中的值是否存在
    System.out.println("optional isPresent:" + Optional.empty().isPresent());
    System.out.println("optional isPresent:" + Optional.of("isPresent").isPresent());

    // 如果值存在則使用該值調(diào)用 consumer , 否則不做任何事情
    Optional.of("exist").ifPresent(opt -> {
        System.out.println("optional value:" + opt);
    });
    Optional.empty().ifPresent(opt -> {
        System.out.println("optional value:" + opt);
    });

運(yùn)行結(jié)果:

optional isPresent:false
optional isPresent:true
optional value:exist

2.5斯碌、判斷是否相等

  • public boolean equals(Object obj):判斷其他對(duì)象是否等于 Optional。Optional 實(shí)例中的 value 為 NULL 也不會(huì)有異常肛度,而是會(huì)正常進(jìn)行比較傻唾。
public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (!(obj instanceof Optional)) {
            return false;
        }

        Optional<?> other = (Optional<?>) obj;
        return Objects.equals(value, other.value);
    }

2.6、其他 Lambda 表達(dá)式的操作

  • public Optional<T> filter(Predicate<? super T> predicate):如果值存在承耿,并且這個(gè)值匹配給定的 predicate冠骄,返回一個(gè)Optional用以描述這個(gè)值,否則返回一個(gè)空的Optional
public Optional<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
    }
  • public<U> Optional<U> map(Function<? super T, ? extends U> mapper):如果有值加袋,則對(duì)其執(zhí)行調(diào)用映射函數(shù)得到返回值凛辣。如果返回值不為 null,則創(chuàng)建包含映射返回值的Optional作為map方法返回值职烧,否則返回空Optional
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Optional.ofNullable(mapper.apply(value));
        }
    }
  • public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper):如果值存在蟀给,返回基于Optional包含的映射方法的值,否則返回一個(gè)空的Optional
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Objects.requireNonNull(mapper.apply(value));
        }
    }

示例代碼:

    // filter() 如果值存在阳堕,并且這個(gè)值匹配給定的 predicate,返回一個(gè)Optional用以描述這個(gè)值择克,否則返回一個(gè)空的Optional
    Optional.of("filter").filter(str -> str.equals("filter")).ifPresent(str -> System.out.println("optional value:" + str));
    System.out.println("optional isPresent:" + Optional.empty().filter(str -> str.equals("filter")).isPresent());

    // map() 方法將Optional中的包裝對(duì)象用Function函數(shù)進(jìn)行運(yùn)算恬总,并包裝成新的Optional對(duì)象
    System.out.println("[map]轉(zhuǎn)化成大寫(xiě):" + Optional.of("map").map(opt -> opt.toUpperCase()).get());

    // flatMap() 方法與map()方法類似,區(qū)別在于mapping函數(shù)的返回值不同肚邢。
    // map()方法的mapping函數(shù)返回值可以是任何類型T壹堰,而flatMap()方法的mapping函數(shù)必須是Optional
    System.out.println("[flatMap]轉(zhuǎn)化成大寫(xiě):" + Optional.of("flatMap").flatMap(opt -> Optional.of(opt.toUpperCase())).get());

運(yùn)行結(jié)果:

optional value:filter
optional isPresent:false
[map]轉(zhuǎn)化成大寫(xiě):MAP
[flatMap]轉(zhuǎn)化成大寫(xiě):FLATMAP

2.7、其他方法

  • public int hashCode():返回存在值的哈希碼骡湖,如果值不存在 返回 0
public int hashCode() {
        return Objects.hashCode(value);
    }
  • public String toString():返回一個(gè)Optional的非空字符串贱纠,用來(lái)調(diào)試
public String toString() {
        return value != null
            ? String.format("Optional[%s]", value)
            : "Optional.empty";
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市响蕴,隨后出現(xiàn)的幾起案子谆焊,更是在濱河造成了極大的恐慌,老刑警劉巖浦夷,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辖试,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡劈狐,警方通過(guò)查閱死者的電腦和手機(jī)罐孝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)肥缔,“玉大人莲兢,你說(shuō)我怎么就攤上這事。” “怎么了改艇?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵收班,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我遣耍,道長(zhǎng)闺阱,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任舵变,我火速辦了婚禮酣溃,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘纪隙。我一直安慰自己赊豌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布绵咱。 她就那樣靜靜地躺著碘饼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪悲伶。 梳的紋絲不亂的頭發(fā)上艾恼,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音麸锉,去河邊找鬼钠绍。 笑死,一個(gè)胖子當(dāng)著我的面吹牛花沉,可吹牛的內(nèi)容都是我干的柳爽。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼碱屁,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼磷脯!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起娩脾,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤赵誓,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后柿赊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體架曹,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年闹瞧,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了绑雄。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡奥邮,死狀恐怖万牺,靈堂內(nèi)的尸體忽然破棺而出罗珍,到底是詐尸還是另有隱情,我是刑警寧澤脚粟,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布覆旱,位于F島的核電站,受9級(jí)特大地震影響核无,放射性物質(zhì)發(fā)生泄漏扣唱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一团南、第九天 我趴在偏房一處隱蔽的房頂上張望噪沙。 院中可真熱鬧,春花似錦吐根、人聲如沸正歼。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)局义。三九已至,卻和暖如春冗疮,著一層夾襖步出監(jiān)牢的瞬間萄唇,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工术幔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留穷绵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓特愿,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親勾缭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子揍障,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容