java8 -函數式編程之Optional

前言

    在某些狀況下,首先要判斷某個參數或者某個方法的返回值是否爲null,才能繼續操做該參數。對於某些鏈式操做須要屢次經過if語句判斷是否爲空,才能確保不拋出NullPointerException,這段非空判斷的代碼顯得很是冗長和噁心。好比下面這段代碼:java

String isoCode = "default";
if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            isocode = country.getIosCode();
            if (isocode != null) {
                isocode = isocode.toUpperCase();
            }
        }
    }
}

    在java 8裏,JDK引入了一個Optional類,該類是一個能夠爲null的容器對象。若是值存在則isPresent()方法會返回true,調用get()方法會返回該對象。經過本文的學習,咱們看下如何經過Optional類重寫上面那段判空代碼。ios

    接下來,咱們一塊兒學習Optional類的初始化和它裏面的方法。lambda表達式和四個基本函數式接口是本文的基礎,能夠經過 java8 -函數式編程之Lambda表達式 和 java8 -函數式編程之四個基本接口 充分了解。編程

Optional初始化

    Optional類的構造方法是私有方法,因此只能經過它的靜態工廠方法進行初始化。它的初始化方法有以下四種:app

(1) <T> Optional<T> of (T value) :爲非null的值建立一個Optional。若是傳入參數爲null,拋出NullPointerException。函數式編程

//調用工廠方法建立Optional實例
Optional<String> name = Optional.of("hello");
//傳入參數爲null,拋出NullPointerException.
Optional<String> someNull = Optional.of(null);

(2)<T> Optional<T> ofNullable (T value) :爲指定的值建立一個Optional,若是指定的值爲null,則返回一個空的Optional。它和 of 的區別是能夠傳null值。在它的實現代碼中,若是傳的值爲null,會調用另外一個靜態工廠方法 empty 獲取一個Optional對象函數

Optional empty = Optional.ofNullable(null);

(3)<T> Optional<T> empty () :ofNullable靜態工廠方法,傳null值時的實現,返回一個空的Optional。學習

Optional類的其它方法

(1)isPresent :若是值存在返回true,不然返回false。測試

// false
Optional<String> empty = Optional.ofNullable(null);
System.out.println(empty.isPresent());

// true
Optional<String> optionalS2 = Optional.of(s2);
System.out.println(optionalS2.isPresent());

(2)get:若是Optional有值則將其返回,不然拋出NoSuchElementExceptionspa

//獲取hello
Optional.of("hello").get();
//拋出NoSuchElementException
Optional.empty().get();

(3)void ifPresent (Consumer<? super T> consumer) :若是Optional實例有值則調用consumer,不然不作處理。.net

//調用ifPresent方法裏面的consumer
Optional.of("hello")
        .ifPresent(System.out::println);

(4)orElse:若是有值則將其返回,不然返回指定的其它值

//輸出:null
System.out.println(Optional.empty().orElse("null"));
//輸出:hello
System.out.println(Optional.of("hello").orElse("null"));

(5)T orElseGet (Supplier<? extends T> other) :orElseGet與orElse方法相似,區別在於獲得的默認值。orElse方法將傳入的字符串做爲默認值,orElseGet方法能夠接受 Supplier接口 的實現用來生成默認值。

//輸出null
System.out.println(Optional.empty().orElseGet(() -> "null"));
//輸出hello
System.out.println(Optional.of("hello").orElseGet(() -> "null"));

(6)<X extends Throwable> T orElseThrow (Supplier<? extends X> exceptionSupplier) throws X :若是有值則將其返回,不然拋出supplier接口建立的異常。

//拋出exception
try {
    Optional.empty().orElseThrow(()->new Exception("爲空"));
} catch (Exception e) {
    e.printStackTrace();
}

(7)<U> Optional<U> map (Function<? super T, ? extends U> mapper) :若是參數 mapper 有值,則調用map方法執行mapper參數的Function方法獲得返回值。若是mapper的返回值不爲null,則建立包含mapping返回值的Optional做爲map方法返回值,不然返回空Optional。若是傳入的mapper參數是null,拋出NullPointerException。

//輸出 JACK
Optional<String> stringOptional = Optional.of("jack").map((value) -> value.toUpperCase());
System.out.println(stringOptional.orElse("default"));

//輸出 default
Optional<String> stringOptional1 = Optional.of("jack").map((value) -> null);
System.out.println(stringOptional1.orElse("default"));

//輸出 default,而且不會調用mapper
String s2 = null;
Optional<String> stringOptional2 = Optional.ofNullable(s2).map((value) -> value.toUpperCase());
System.out.println(stringOptional2.orElse("default"));

//若是參數mapper爲null,拋NullPointerException異常
try {
    String s3 = null;
    Optional<String> stringOptional3 = Optional.ofNullable(s3).map(null);
    System.out.println(stringOptional3.orElse("default"));
} catch (Exception e) {
}

(8)<U> Optional<U> flatMap (Function<? super T, Optional<U>> mapper) :flatMap與map方法相似,區別在於flatMap中的mapper返回值必須是Optional。調用結束時,flatMap不會對結果用Optional封裝。

//flatMap,輸出 JACK
Optional<String> stringOptional4 = Optional.of("jack").flatMap((value) -> Optional.ofNullable(value.toUpperCase()));
System.out.println(stringOptional4.orElse("default"));

//flatMap,輸出 default
Optional<String> stringOptional5 = Optional.of("jack").flatMap((value) -> Optional.ofNullable(null));
System.out.println(stringOptional5.orElse("default"));

//flatMap,輸出 default,而且不會調用mapper
String s6 = null;
Optional<String> stringOptional6 = Optional.ofNullable(s6).flatMap((value) -> Optional.ofNullable(value.toUpperCase()));
System.out.println(stringOptional6.orElse("default"));

//flatMap 若是map的參數mapper爲null,拋NullPointerException異常
try {
    String s7 = null;
    Optional<String> stringOptional7 = Optional.ofNullable(s7).flatMap(null);
    System.out.println(stringOptional7.orElse("default"));
} catch (Exception e) {
    System.out.println("出錯了");
}

(9)Optional<T> filter (Predicate<? super T> predicate) :若是有值而且知足斷言條件返回包含該值的Optional,不然返回空Optional。

//輸出default
String filterString = Optional.of("hugo")
        .filter(s -> "jack".equals(s))
        .orElse("default");
System.out.println(filterString);
//輸出hugo
String filterString2 = Optional.of("hugo")
        .filter(s -> "hugo".equals(s))
        .orElse("default");
System.out.println(filterString2);
//輸出default,斷言接口裏面的語句不會執行
String nullableString = null;
String filterString3 = Optional.ofNullable(nullableString)
        .filter(s -> {
            System.out.println("測試是否調用");
            return "jack".equals(s);
        })
        .orElse("default");
System.out.println(filterString3);

 

解決問題

通過上面學習Optional的相關API,已經對它有了必定的瞭解。下面,咱們運用上面的知識解決在前言中遺留的問題。

ioscode = Optional.ofNullable(user)
        .map(u -> u.getAddress())
        .map(addr -> addr.getCountry())
        .map(country -> country.getIosCode())
        .map(String::toUpperCase)
        .orElse("default");

從上面的學習能夠知道,只有Optional是empty的,map方法不會被調用。

相關資料

Java 8 函數式編程系列

    java8 -函數式編程之Lambda表達式

    java8 -函數式編程之四個基本接口

    java8 -函數式編程之Optional

    java8 -函數式編程之Stream

相關文章
相關標籤/搜索