最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java8深入學(xué)習(xí)之熟透Optional

 更新時間:2019年09月22日 14:25:26   作者:LanceToBigData  
這篇文章主要給大家介紹了關(guān)于Java8深入學(xué)習(xí)之熟透Optional的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Java8具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧

一、使用Optional引言

1.1、代碼問題引出

在寫程序的時候一般都遇到過 NullPointerException,所以經(jīng)常會對程序進(jìn)行非空的判斷:

User user = getUserById(id);
if (user != null) {
 String username = user.getUsername();
 System.out.println("Username is: " + username); // 使用 username
}

為了解決這種尷尬的處境,JDK 終于在 Java8 的時候加入了 Optional 類,查看 Optional 的 javadoc 介紹:

A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.

這是一個可以包含或者不包含非 null 值的容器。如果值存在則 isPresent()方法會返回 true,調(diào)用 get() 方法會返回該對象。

1.2、解決進(jìn)階

我們假設(shè) getUserById 已經(jīng)是個客觀存在的不能改變的方法,那么利用 isPresent 和 get 兩個方法,我們現(xiàn)在能寫出下面的代碼:

Optional<User> user = Optional.ofNullable(getUserById(id));
if (user.isPresent()) {
 String username = user.get().getUsername();
 System.out.println("Username is: " + username); // 使用 username
}

好像看著代碼是優(yōu)美了點,但是事實上這與之前判斷 null 值的代碼沒有本質(zhì)的區(qū)別,反而用 Optional 去封裝 value,增加了代碼量。所以我們來看看 Optional 還提供了哪些方法,讓我們更好的(以正確的姿勢)使用 Optional。

二、Optional三個靜態(tài)構(gòu)造方法

1)概述:

JDK 提供三個靜態(tài)方法來構(gòu)造一個 Optional:

1、Optional.of(T value)

 public static <T> Optional<T> of(T value) {
  return new Optional<>(value);
 }

該方法通過一個非 null 的 value 來構(gòu)造一個 Optional,返回的 Optional 包含了 value 這個值。對于該方法,傳入的參數(shù)一定不能為 null,否則便會拋出 NullPointerException。

2、Optional.ofNullable(T value)

 public static <T> Optional<T> ofNullable(T value) {
  return value == null ? empty() : of(value);
 }

該方法和 of 方法的區(qū)別在于,傳入的參數(shù)可以為 null —— 但是前面 javadoc 不是說 Optional 只能包含非 null 值嗎?我們可以看看 ofNullable 方法的源碼。

原來該方法會判斷傳入的參數(shù)是否為 null,如果為 null 的話,返回的就是 Optional.empty()。

3、Optional.empty()

 public static<T> Optional<T> empty() {
  @SuppressWarnings("unchecked")
  Optional<T> t = (Optional<T>) EMPTY;
  return t;
 }

該方法用來構(gòu)造一個空的 Optional,即該 Optional 中不包含值 —— 其實底層實現(xiàn)還是 如果 Optional 中的 value 為 null 則該 Optional 為不包含值的狀態(tài),然后在 API 層面將 Optional 表現(xiàn)的不能包含 null值,使得 Optional 只存在 包含值 和 不包含值 兩種狀態(tài)。

2)分析:

前面 javadoc 也有提到,Optional 的 isPresent() 方法用來判斷是否包含值,get() 用來獲取 Optional 包含的值 —— 值得注意的是,如果值不存在,即在一個Optional.empty 上調(diào)用 get() 方法的話,將會拋出 NoSuchElementException異常。

3)總結(jié):

1)Optional.of(obj): 它要求傳入的 obj 不能是 null 值的, 否則還沒開始進(jìn)入角色就倒在了 NullPointerException 異常上了.

2)Optional.ofNullable(obj): 它以一種智能的, 寬容的方式來構(gòu)造一個 Optional 實例. 來者不拒, 傳 null 進(jìn)到就得到 Optional.empty(), 非 null 就調(diào)用 Optional.of(obj).

那是不是我們只要用 Optional.ofNullable(obj) 一勞永逸, 以不變應(yīng)二變的方式來構(gòu)造 Optional 實例就行了呢? 那也未必, 否則 Optional.of(obj) 何必如此暴露呢, 私有則可。

三、Optional常用方法詳解

3.1、Optional常用方法概述

Optional.of(T t)

將指定值用 Optional 封裝之后返回,如果該值為 null,則拋出一個 NullPointerException 異常。

Optional.empty()

創(chuàng)建一個空的 Optional 實例。

Optional.ofNullable(T t)

將指定值用 Optional 封裝之后返回,如果該值為 null,則返回一個空的 Optional 對象。

isPresent

如果值存在返回true,否則返回false

ifPresent

如果Optional實例有值則為其調(diào)用consumer ,否則不做處理。
要理解ifPresent方法,首先需要了解Consumer類。簡答地說,Consumer類包含一個抽象方法。該抽象方法對傳入的值進(jìn)行處理,但沒有返回值。 Java8支持不用接口直接通過lambda表達(dá)式傳入?yún)?shù)。
如果Optional實例有值,調(diào)用ifPresent()可以接受接口段或lambda表達(dá)式。

Optional.get()

如果該值存在,將該值用 Optional 封裝返回,否則拋出一個 NoSuchElementException 異常。

orElse(T t)

如果調(diào)用對象包含值,返回該值,否則返回t。

orElseGet(Supplier s)

如果調(diào)用對象包含值,返回該值,否則返回 s 獲取的值。

orElseThrow()

它會在對象為空的時候拋出異常。

map(Function f)

如果值存在,就對該值執(zhí)行提供的 mapping 函數(shù)調(diào)用。

flatMap(Function mapper)

如果值存在,就對該值執(zhí)行提供的mapping 函數(shù)調(diào)用,返回一個 Optional 類型的值,否則就返回一個空的 Optional 對象。

3.2、Optional常用方法詳解

3.2.1、ifPresent

  public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
      consumer.accept(value);
  }

如果 Optional 中有值,則對該值調(diào)用 consumer.accept,否則什么也不做。
所以對于引言上的例子,我們可以修改為:

Optional<User> user = Optional.ofNullable(getUserById(id));
user.ifPresent(u -> System.out.println("Username is: " + u.getUsername()));

3.2.2、orElse

  public T orElse(T other) {
    return value != null ? value : other;
  }

如果 Optional 中有值則將其返回,否則返回 orElse 方法傳入的參數(shù)。

User user = Optional
    .ofNullable(getUserById(id))
    .orElse(new User(0, "Unknown"));
    
System.out.println("Username is: " + user.getUsername());

3.2.3、orElseGet

  public T orElseGet(Supplier<? extends T> other) {
    return value != null ? value : other.get();
  }

orElseGet 與 orElse 方法的區(qū)別在于,orElseGet 方法傳入的參數(shù)為一個 Supplier接口的實現(xiàn) —— 當(dāng) Optional 中有值的時候,返回值;當(dāng) Optional 中沒有值的時候,返回從該 Supplier 獲得的值。

User user = Optional
    .ofNullable(getUserById(id))
    .orElseGet(() -> new User(0, "Unknown"));
    
System.out.println("Username is: " + user.getUsername());

3.2.4、orElseThrow

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
      return value;
    } else {
      throw exceptionSupplier.get();
    }
  }

orElseThrow 與 orElse 方法的區(qū)別在于,orElseThrow 方法當(dāng) Optional 中有值的時候,返回值;沒有值的時候會拋出異常,拋出的異常由傳入的 exceptionSupplier 提供。

舉例說明:

​ 在 SpringMVC 的控制器中,我們可以配置統(tǒng)一處理各種異常。查詢某個實體時,如果數(shù)據(jù)庫中有對應(yīng)的記錄便返回該記錄,否則就可以拋出 EntityNotFoundException ,處理 EntityNotFoundException 的方法中我們就給客戶端返回Http 狀態(tài)碼 404 和異常對應(yīng)的信息 —— orElseThrow 完美的適用于這種場景。

@RequestMapping("/{id}")
public User getUser(@PathVariable Integer id) {
  Optional<User> user = userService.getUserById(id);
  return user.orElseThrow(() -> new EntityNotFoundException("id 為 " + id + " 的用戶不存在"));
}

@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<String> handleException(EntityNotFoundException ex) {
  return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}

3.2.5、map

  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));
    }
  }

如果當(dāng)前 Optional 為 Optional.empty,則依舊返回 Optional.empty;否則返回一個新的 Optional,該 Optional 包含的是:函數(shù) mapper 在以 value 作為輸入時的輸出值。

String username = Optional.ofNullable(getUserById(id))
            .map(user -> user.getUsername())
            .orElse("Unknown")
            .ifPresent(name -> System.out.println("Username is: " + name));

而且我們可以多次使用 map 操作:

Optional<String> username = Optional.ofNullable(getUserById(id))
                .map(user -> user.getUsername())
                .map(name -> name.toLowerCase())
                .map(name -> name.replace('_', ' '))
                .orElse("Unknown")
                .ifPresent(name -> System.out.println("Username is: " + name));

3.2.6、flatMap

  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));
    }
  }

flatMap 方法與 map 方法的區(qū)別在于,map 方法參數(shù)中的函數(shù) mapper 輸出的是值,然后 map 方法會使用 Optional.ofNullable 將其包裝為 Optional;而 flatMap 要求參數(shù)中的函數(shù) mapper 輸出的就是 Optional。

Optional<String> username = Optional.ofNullable(getUserById(id))
                .flatMap(user -> Optional.of(user.getUsername()))
                .flatMap(name -> Optional.of(name.toLowerCase()))
                .orElse("Unknown")
                .ifPresent(name -> System.out.println("Username is: " + name));

3.2.7、filter

  public Optional<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    if (!isPresent())
      return this;
    else
      return predicate.test(value) ? this : empty();
  }

filter 方法接受一個 Predicate 來對 Optional 中包含的值進(jìn)行過濾,如果包含的值滿足條件,那么還是返回這個 Optional;否則返回 Optional.empty。

Optional<String> username = Optional.ofNullable(getUserById(id))
                .filter(user -> user.getId() < 10)
                .map(user -> user.getUsername());
                .orElse("Unknown")
                .ifPresent(name -> System.out.println("Username is: " + name));

四、Optional使用示例

4.1、使用展示一

當(dāng) user.isPresent() 為真, 獲得它關(guān)聯(lián)的 orders的映射集合, 為假則返回一個空集合時, 我們用上面的 orElse, orElseGet 方法都乏力時, 那原本就是 map 函數(shù)的責(zé)任, 我們可以這樣一行:

return user.map(u -> u.getOrders()).orElse(Collections.emptyList())
 
//上面避免了我們類似 Java 8 之前的做法
if(user.isPresent()) {
 return user.get().getOrders();
} else {
 return Collections.emptyList();
}

map 是可能無限級聯(lián)的, 比如再深一層, 獲得用戶名的大寫形式:

return user.map(u -> u.getUsername())
      .map(name -> name.toUpperCase())
      .orElse(null);

以前的做法:

User user = .....
if(user != null) {
 String name = user.getUsername();
 if(name != null) {
  return name.toUpperCase();
 } else {
  return null;
 }
} else {
 return null;
}

filter() :如果有值并且滿足條件返回包含該值的Optional,否則返回空Optional。

Optional<String> longName = name.filter((value) -> value.length() > 6); 
System.out.println(longName.orElse("The name is less than 6 characters"));

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對腳本之家的支持。

相關(guān)文章

  • 在SpringBoot中如何使用HttpClient實現(xiàn)HTTP請求

    在SpringBoot中如何使用HttpClient實現(xiàn)HTTP請求

    本文介紹了如何使用Apache?HttpClient來訪問HTTP協(xié)議的資源,并提供了詳細(xì)的使用示例,包括GET和POST請求的無參和有參調(diào)用
    2025-02-02
  • Java中的StringJoiner類使用示例深入詳解

    Java中的StringJoiner類使用示例深入詳解

    這篇文章主要為大家介紹了Java中的StringJoiner類使用示例深入詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • Java 中IO流字符流詳解及實例

    Java 中IO流字符流詳解及實例

    這篇文章主要介紹了Java 中IO流字符流詳解及實例的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • Java中使用qsort對類進(jìn)行排序的操作代碼

    Java中使用qsort對類進(jìn)行排序的操作代碼

    這篇文章主要介紹了JAVA中如何使用qsort對類進(jìn)行排序,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-09-09
  • Java GUI制作簡單的管理系統(tǒng)

    Java GUI制作簡單的管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了Java GUI制作簡單的管理系統(tǒng)的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • SpringBoot從配置文件中獲取屬性的四種方法總結(jié)

    SpringBoot從配置文件中獲取屬性的四種方法總結(jié)

    這篇文章主要介紹了SpringBoot從配置文件中獲取屬性的四種方法總結(jié),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • Java初始化塊及執(zhí)行過程解析

    Java初始化塊及執(zhí)行過程解析

    這篇文章主要介紹了Java初始化塊及執(zhí)行過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-09-09
  • SpringBoot使用@SpringBootTest注解開發(fā)單元測試教程

    SpringBoot使用@SpringBootTest注解開發(fā)單元測試教程

    這篇文章主要介紹了SpringBoot使用@SpringBootTest注解開發(fā)單元測試教程,本文通過詳細(xì)的案例過程來說明如何使用該項技術(shù),需要的朋友可以參考下
    2021-06-06
  • Java實現(xiàn)貪吃蛇游戲源碼

    Java實現(xiàn)貪吃蛇游戲源碼

    這篇文章主要為大家詳細(xì)介紹了Java實現(xiàn)貪吃蛇游戲源碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • SpringBoot多環(huán)境配置及日志記錄器詳解

    SpringBoot多環(huán)境配置及日志記錄器詳解

    這篇文章主要介紹了SpringBoot多環(huán)境配置及日志記錄器詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2024-01-01

最新評論

延庆县| 汉中市| 冕宁县| 莎车县| 隆尧县| 石狮市| 建平县| 穆棱市| 阿图什市| 长治市| 绥芬河市| 南充市| 淮阳县| 泰州市| 乌鲁木齐县| 丰都县| 兴业县| 泗阳县| 高青县| 定州市| 四子王旗| 南充市| 安康市| 平阴县| 沙洋县| 平顺县| 仙居县| 彰化市| 平邑县| 波密县| 怀宁县| 邛崃市| 城口县| 罗平县| 巴林右旗| 大冶市| 景泰县| 九江县| 沛县| 鄂伦春自治旗| 庐江县|