Optional類詳解


簡述

  Optional類是java8中引入的一個非常有用的類,主要用處是解決編程中的空指針異常,本質上,這是一個包含有可選值的包裝類,這意味着 Optional 類既可以含有對象也可以為空。Optional 是 Java 實現函數式編程的強勁一步,並且幫助在范式中實現。

空指針異常的麻煩

  在java8之前,任何訪問對象方法或屬性的調用都有可能導致空指針異常,例如:

String isocode = user.getAddress().getCountry().getIsocode().toUpperCase();

  這行代碼如果我們需要確保不觸發異常,我們就要寫成:

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

創建Optional實例

  使用empty()創建空實例

Optional<User> emptyOpt = Optional.empty();

  嘗試訪問emptyOpt變量的值會導致NoSuchElementException

  使用of()或ofNullable()方法創建包含值的Optional,不同之處在於:如果你把 null 值作為參數傳遞進去,of() 方法會拋出 NullPointerException

Optional<User> opt1 = Optional.of(user);
Optional<User> opt1 = Optional.ofNullable(user);

訪問Optional對象的值

  使用get()方法獲取Optional的值

Optional<User> opt1 = Optional.of(user);
User tmp = opt1.get();

  get方法會在值為null的時候拋出異常,我們可以用ifPresent()方法驗證值是否為空

返回默認值

  orElse()方法可以在創建實例時就指定返回的默認值

User user = null;
User user2 = new User("anna@gmail.com", "1234");
User result = Optional.ofNullable(user).orElse(user2);

  因為user是空,所以此時我們想獲取result的值的話會得到user2

  我們也可以使用orElseGet(),如果沒有值,它會執行作為參數傳入的 Supplier(供應者) 函數式接口,並將返回其執行結果

User result = Optional.ofNullable(user).orElseGet( () -> user2);

  不同的是使用orElse的話無論創建的值是否為空,都會orElse里的代碼,如果里面有創建新的實例,這會對性能產生很大影響

  另外我們可以使用orElseThrow(),它會在對象為空的時候拋出異常,而不是返回備選的值

User result = Optional.ofNullable(user)
        .orElseThrow( () -> new IllegalArgumentException());

  此時如果user為空,會拋出我們定義的異常IllegalArgumentException

轉換值

  我們可以使用map方法,將 Optional里的元素進行轉換

User user = new User("anna@gmail.com", "1234");
String email = Optional.ofNullable(user)
        .map(u -> u.getEmail()).orElse("default@gmail.com");

  注意無論是user為null,還是user里的Email為空,都會觸發返回orElse里的默認值,這也就Optional的map操作的鏈式調用的精髓,我們可以不斷的接着寫map,無需一次次地判斷是否為空

  注意如果當對象發生Optinoal嵌套的時候,我們需要使用flatMap方法,詳細請看:https://blog.csdn.net/qq_35634181/article/details/101109300

過濾值

  filter()接受一個Predicate參數,返回測試結果為 true 的值

  用法和stream的filter一模一樣,例如我們可以檢查用戶的郵箱是否帶@

User user = new User("anna@gmail.com", "1234");
Optional<User> result = Optional.ofNullable(user)
        .filter(u -> u.getEmail() != null && u.getEmail().contains("@"));

對原來if的改進

  對於User類我們對其進行重構,使其getter方法返回Optional類

public class User {
    private Address address;

    public Optional<Address> getAddress() {
        return Optional.ofNullable(address);
    }

    // ...
}
public class Address {
    private Country country;

    public Optional<Country> getCountry() {
        return Optional.ofNullable(country);
    }

    // ...
}
View Code

  上面的嵌套結構可以用下面的圖來表示:

  之前冗雜的if判斷我們就可以改成這樣:

String result = Optional.ofNullable(user)
        .flatMap(u -> u.getAddress())
        .flatMap(a -> a.getCountry())
        .map(c -> c.getIsocode())
        .orElse("default");

  也可以簡寫成這樣:

String result = Optional.ofNullable(user)
  .flatMap(User::getAddress)
  .flatMap(Address::getCountry)
  .map(Country::getIsocode)
  .orElse("default");

Reference

  https://blog.csdn.net/wwe4023/article/details/80760416

  https://blog.csdn.net/qq_35634181/article/details/101109300


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM