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

使用Java8中Optional機(jī)制的正確姿勢(shì)

 更新時(shí)間:2017年11月02日 12:02:48   作者:隔葉黃鶯  
我們知道 Java 8 增加了一些很有用的 API, 其中一個(gè)就是 Optional,下面這篇文章主要給大家介紹了關(guān)于如何正確使用Java8中Optional機(jī)制的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧。

前言

Java8帶來(lái)的函數(shù)式編程特性對(duì)于習(xí)慣命令式編程的程序員來(lái)說(shuō)還是有一定的障礙的,我們只有深入了解這些機(jī)制的方方面面才能運(yùn)用自如。Null的處理在JAVA編程中是出了try catch之外的另一個(gè)頭疼的問(wèn)題,需要大量的非空判斷模板代碼,程序邏輯嵌套層次太深。尤其是對(duì)集合的使用,需要層層判空。

首先來(lái)看下Optional類的結(jié)構(gòu)圖:

而如果我們對(duì)它不稍假探索, 只是輕描淡寫的認(rèn)為它可以優(yōu)雅的解決 NullPointException 的問(wèn)題, 于是代碼就開始這么寫了

Optional<User> user = ...... 
if (user.isPresent()) {
 return user.getOrders();
} else {
 return Collections.emptyList();
}

那么不得不說(shuō)我們的思維仍然是在原地踏步, 只是本能的認(rèn)為它不過(guò)是 User 實(shí)例的包裝, 這與我們之前寫成

User user = .....
if (user != null) {
 return user.getOrders();
} else {
 return Collections.emptyList();
}

實(shí)質(zhì)上是沒有任何分別. 這就是我們將要講到的使用好 Java 8 Optional 類型的正確姿勢(shì).

在里約奧運(yùn)之時(shí), 新聞一再提起五星紅旗有問(wèn)題, 可是我怎么看都看不出來(lái)有什么問(wèn)題, 后來(lái)才道是小星星膜拜中央的姿勢(shì)不對(duì). 因此我們千萬(wàn)也別對(duì)自己習(xí)以為常的事情覺得理所當(dāng)然, 絲毫不會(huì)覺得有何不妥, 換句話說(shuō)也就是當(dāng)我們切換到 Java 8 的 Optional 時(shí), 不能繼承性的對(duì)待過(guò)往 null 時(shí)的那種思維, 應(yīng)該掌握好新的, 正確的使用 Java 8 Optional 的正確姿勢(shì).

直白的講, 當(dāng)我們還在以如下幾種方式使用 Optional 時(shí), 就得開始檢視自己了

  • 調(diào)用 isPresent() 方法時(shí)
  • 調(diào)用 get() 方法時(shí)
  • Optional 類型作為類/實(shí)例屬性時(shí)
  • Optional 類型作為方法參數(shù)時(shí)

isPresent() obj != null 無(wú)任何分別, 我們的生活依然在步步驚心. 而沒有 isPresent() 作鋪墊的 get() 調(diào)用在 IntelliJ IDEA 中會(huì)收到告警

Reports calls to java.util.Optional.get() without first checking with a isPresent() call if a value is available. If the Optional does not contain a value, get() will throw an exception. (調(diào)用 Optional.get() 前不事先用 isPresent() 檢查值是否可用. 假如 Optional 不包含一個(gè)值, get() 將會(huì)拋出一個(gè)異常)

把 Optional 類型用作屬性或是方法參數(shù)在 IntelliJ IDEA 中更是強(qiáng)力不推薦的

Reports any uses of java.util.Optional<T>, java.util.OptionalDouble, java.util.OptionalInt, java.util.OptionalLong or com.google.common.base.Optional as the type for a field or a parameter. Optional was designed to provide a limited mechanism for library method return types where there needed to be a clear way to represent "no result". Using a field with type java.util.Optional is also problematic if the class needs to be Serializable, which java.util.Optional is not. (使用任何像 Optional 的類型作為字段或方法參數(shù)都是不可取的. Optional 只設(shè)計(jì)為類庫(kù)方法的, 可明確表示可能無(wú)值情況下的返回類型. Optional 類型不可被序列化, 用作字段類型會(huì)出問(wèn)題的)

所以 Optional 中我們真正可依賴的應(yīng)該是除了 isPresent()get() 的其他方法:

  • public<U> Optional<U> map(Function<? super T, ? extends U> mapper)
  • public T orElse(T other)
  • public T orElseGet(Supplier<? extends T> other)
  • public void ifPresent(Consumer<? super T> consumer)
  • public Optional<T> filter(Predicate<? super T> predicate)
  • public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)
  • public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X

我略有自信的按照它們大概使用頻度對(duì)上面的方法排了一下序.

先又不得不提一下 Optional 的三種構(gòu)造方式: Optional.of(obj)Optional.ofNullable(obj) 和明確的 Optional.empty()

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

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

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

我本人的觀點(diǎn)是:  1. 當(dāng)我們非常非常的明確將要傳給 Optional.of(obj) 的 obj 參數(shù)不可能為 null 時(shí), 比如它是一個(gè)剛 new 出來(lái)的對(duì)象(Optional.of(new User(...))) , 或者是一個(gè)非 null 常量時(shí);  2. 當(dāng)想為 obj 斷言不為 null 時(shí), 即我們想在萬(wàn)一 obj 為 null 立即報(bào)告 NullPointException 異常, 立即修改, 而不是隱藏空指針異常時(shí), 我們就應(yīng)該果斷的用 Optional.of(obj) 來(lái)構(gòu)造 Optional 實(shí)例, 而不讓任何不可預(yù)計(jì)的 null 值有可乘之機(jī)隱身于 Optional 中.

現(xiàn)在才開始怎么去使用一個(gè)已有的 Optional 實(shí)例, 假定我們有一個(gè)實(shí)例 Optional<User> user , 下面是幾個(gè)普遍的, 應(yīng)避免 if(user.isPresent()) { ... } else { ... } 幾中應(yīng)用方式.

存在即返回, 無(wú)則提供默認(rèn)值

return user.orElse(null); //而不是 return user.isPresent() ? user.get() : null;
return user.orElse(UNKNOWN_USER); 

存在即返回, 無(wú)則由函數(shù)來(lái)產(chǎn)生

return user.orElseGet(() -> fetchAUserFromDatabase()); //而不要 return user.isPresent() ? user: fetchAUserFromDatabase();

存在才對(duì)它做點(diǎn)什么

user.ifPresent(System.out::println);
 
//而不要下邊那樣
if (user.isPresent()) {
 System.out.println(user.get());
}

map 函數(shù)隆重登場(chǎng)

當(dāng) user.isPresent() 為真, 獲得它關(guān)聯(lián)的 orders, 為假則返回一個(gè)空集合時(shí), 我們用上面的 orElse, orElseGet 方法都乏力時(shí), 那原本就是 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  是可能無(wú)限級(jí)聯(lián)的, 比如再深一層, 獲得用戶名的大寫形式

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

這要擱在以前, 每一級(jí)調(diào)用的展開都需要放一個(gè) null 值的判斷

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

針對(duì)這方面 Groovy 提供了一種安全的屬性/方法訪問(wèn)操作符 ?.

user?.getUsername()?.toUpperCase();

Swift 也有類似的語(yǔ)法, 只作用在  Optional 的類型上.

用了 isPresent() 處理 NullPointerException 不叫優(yōu)雅, 有了  orElse, orElseGet 等, 特別是 map 方法才叫優(yōu)雅.

其他幾個(gè), filter() 把不符合條件的值變?yōu)?empty()flatMap() 總是與 map() 方法成對(duì)的,  orElseThrow() 在有值時(shí)直接返回, 無(wú)值時(shí)拋出想要的異常.

一句話小結(jié): 使用 Optional 時(shí)盡量不直接調(diào)用 Optional.get() 方法, Optional.isPresent() 更應(yīng)該被視為一個(gè)私有方法, 應(yīng)依賴于其他像 Optional.orElse() , Optional.orElseGet() ,   Optional.map() 等這樣的方法.

最后, 最好的理解 Java 8 Optional 的方法莫過(guò)于看它的源代碼 java.util.Optional , 閱讀了源代碼才能真真正正的讓你解釋起來(lái)最有底氣, Optional 的方法中基本都是內(nèi)部調(diào)用  isPresent() 判斷, 真時(shí)處理值, 假時(shí)什么也不做.

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • 淺談Spring解決jar包依賴的bom

    淺談Spring解決jar包依賴的bom

    這篇文章主要介紹了淺談Spring解決jar包依賴的bom,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2017-12-12
  • Java 中的字符串常量池詳解

    Java 中的字符串常量池詳解

    本文主要介紹Java中的字符串常量池的知識(shí),這里整理了相關(guān)資料及簡(jiǎn)單示例代碼幫助大家學(xué)習(xí)理解此部分的知識(shí),有需要的小伙伴可以參考下
    2016-09-09
  • Java StringBuilder的用法示例

    Java StringBuilder的用法示例

    這篇文章主要給大家介紹了關(guān)于Java StringBuilder用法的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Java并發(fā)線程池實(shí)例分析講解

    Java并發(fā)線程池實(shí)例分析講解

    這篇文章主要介紹了Java并發(fā)線程池實(shí)例,線程池——控制線程創(chuàng)建、釋放,并通過(guò)某種策略嘗試復(fù)用線程去執(zhí)行任務(wù)的一個(gè)管理框架,從而實(shí)現(xiàn)線程資源與任務(wù)之間一種平衡
    2023-02-02
  • MyBatis-Plus 之selectMaps、selectObjs、selectCount、selectOne的使用

    MyBatis-Plus 之selectMaps、selectObjs、selectCount、selectO

    本文主要介紹了MyBatis-Plus 之selectMaps、selectObjs、selectCount、selectOne的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • 一文徹底搞定Java中常用集合的排序方法

    一文徹底搞定Java中常用集合的排序方法

    在某些特殊的場(chǎng)景下我們需要在Java程序中對(duì)List集合進(jìn)行排序操作,下面這篇文章主要給大家介紹了關(guān)于Java中常用集合的排序方法的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11
  • Java springboot yaml語(yǔ)法注解

    Java springboot yaml語(yǔ)法注解

    這篇文章主要介紹了SpringBoot中的yaml語(yǔ)法及靜態(tài)資源訪問(wèn)問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09
  • servlet的url-pattern匹配規(guī)則詳細(xì)描述(小結(jié))

    servlet的url-pattern匹配規(guī)則詳細(xì)描述(小結(jié))

    在利用servlet或Filter進(jìn)行url請(qǐng)求的匹配時(shí),很關(guān)鍵的一點(diǎn)就是匹配規(guī)則。這篇文章主要介紹了servlet的url-pattern匹配規(guī)則詳細(xì)描述(小結(jié)),非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2018-07-07
  • Java自定義線程池的實(shí)現(xiàn)示例

    Java自定義線程池的實(shí)現(xiàn)示例

    本文主要介紹了Java自定義線程池的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • Java String類常用方法梳理總結(jié)

    Java String類常用方法梳理總結(jié)

    這篇文章主要介紹了Java String類常用方法梳理總結(jié),類 String 中包括用于檢查各個(gè)字符串的方法,比如用于比較字符串,搜索字符串,更多相關(guān)內(nèi)容需要的朋友可以參考一下
    2022-06-06

最新評(píng)論

巴林右旗| 和静县| 丁青县| 青海省| 苏尼特左旗| 西峡县| 海城市| 澄迈县| 塘沽区| 隆子县| 泰安市| 图木舒克市| 五华县| 双流县| 紫阳县| 项城市| 满城县| 成安县| 垫江县| 丘北县| 灵丘县| 犍为县| 泊头市| 邯郸县| 县级市| 梅河口市| 仁化县| 乌兰县| 饶阳县| 项城市| 临夏市| 武定县| 桃江县| 泌阳县| 全椒县| 甘肃省| 溧阳市| 临猗县| 澎湖县| 漳州市| 大英县|