JDK8中Optional類巧用之判空操作

前言

相信大傢肯定所有的開發者都對Java8裡面的所有的東西都感興趣,雖然目前的 JDK 已經更新到 JDK17 瞭,但是我相信,現在很多公司使用的還都是 JDK8 甚至是 JDK7,但是,就算是有些公司已經升級到 JDK8 但是對於 JDK8 裡面的一些東西的使用,卻沒有使用的淋漓盡致。 今天就給大傢放出幾個 JDK8 裡面比較好用的。

JDK8

大傢都是知道 JDK8 就開始使用 Lambda 表達式,但是很多不管是在教程上還是在其他的書籍上,都沒有說在實際開發的時候去使用上這個 Lambda 表達式,而且包括 JDK8 裡面的一些新的類,也都沒有引入,所以阿粉在這裡想要給大傢安利一波使用方面的知識。

Optional類

這個類對於大傢來說,是一個非常重要的類,不知道大傢有沒有被 java.lang.NullPointerException 瘋狂的折磨過,不管是新人開發還是老開發,遇到這個問題的時候,都是頭大的很,因為我們要在代碼裡面去瘋狂的判斷是否是null,如果不是 null 需要怎麼處理,如果是 null 需要怎麼處理,反正就是你要是想解決 java.lang.NullPointerException 這個問題,就免不瞭去加一些判斷條件,而 Optional 這個類,則是幫你優雅的處理 null 的問題。

我們先看一組 Java7 中的一些判斷空的實現:

 User user = usersMapper.selectUserById(userId);
 String userName = user.getUserName();
    if(user!= null){
        if(userName != null && !userName.isEmpty()){
                .....
              }
    }

阿粉相信大傢一定都寫過這個樣子的代碼,因為我們不知道SQL查詢出來的數據中是否包含瞭我們的 Users 對象,如果要是 Users 對象,那麼就會無情的出現 java.lang.NullPointerException 這個空指針異常,這時候就很尷尬瞭,老開發一臉懵逼,我竟然還有的地方沒有驗證?

但是驗證瞭之後,你就會發現代碼量是非常的大,而且有點不太美觀,我們再來對比一下 JDK8 中,給我們提供的方法來進行驗證的方式。

User user = usersMapper.selectUserById(userId);
Optional.ofNullable(user)
        .map(User::getUserName)
        .ifPresent(userName->{
        ....
        }

大傢看這種鏈式編程,ofNullable() 方法給我們提供瞭判斷 user 是不是空,並且去校驗 userName,如果存在,然後執行下面的邏輯,相比較 JDK7 的內容,相信大傢看起來的話肯定是沒有 JDK7 中的表現的那麼的明顯,但是大傢看代碼是不是發現已經被處理的妥妥的瞭。而且非常的優雅。

相信大傢肯定都看過一些教程,上面會寫到:

    User user = usersMapper.selectUserById(userId);
    Optional<User> userOptional = Optional.ofNullable(user);
    Optional<String> str = userOptional.map(User::getUserName);
    ....

但是相對於代碼的可讀性來說,我們肯定還是希望使用 JDK7 上面的判斷來進行判斷,但是這種 JDK8 的鏈式編程,在一定程度上減少瞭代碼量,並且開發效率也會相對應的提升。

如果大傢不信,我們可以來運行一下我們的代碼,然後看一下效果。

Optional.ofNullable(user)
        .map(User::getUserName)
        .ifPresent(userName->{
            System.out.println("用戶UserName不為空");
        });

大傢看,是不是就出現瞭我們想要的結果,一個判斷 null 的操作,瞬間變得高大上瞭,而且代碼的逼格瞬間上升一個檔次。

對於 Optional 類,在 Java8 實戰中給出瞭很多的方法,阿粉也是給大傢摘取瞭一下,做瞭個總結,

  • ofNullable 方法 :將指定值用Optional封裝之後返回,如果該值為null,則返回一個空的Optional對象
  • empty 方法 :返回一個空的Optional實例
  • filter 方法 :如果值存在並且滿足提供的謂詞,就返回包含該值的Optional對象;否則返回一個空的 Optional對象
  • flatMap 方法 :如果值存在,就對該值執行提供的mapping函數調用,返回一個Optional類型的值,否則就返 回一個空的Optional對象
  • get 方法 :如果該值存在,將該值用Optional封裝返回,否則拋出一個NoSuchElementException異常
  • ifPresent 方法 :如果值存在,就執行使用該值的方法調用,否則什麼也不做
  • isPresent 方法 :如果值存在就返回true,否則返回false
  • map 方法 :如果值存在,就對該值執行提供的mapping函數調用
  • of 方法 :將指定值用Optional封裝之後返回,如果該值為null,則拋出一個NullPointerException異常
  • orElse 方法:如果有值則將其返回,否則返回一個默認值
  • orElseGet 方法 :如果有值則將其返回,否則返回一個由指定的Supplier接口生成的值
  • orElseThrow 方法 :如果有值則將其返回,否則拋出一個由指定的Supplier接口生成的異常

大傢看這些方法是不是都有很多相似的,比如 map,flatMap,還有orElse,orElseGet,orElseThrow 方法

map 和 flatMap 比較:

這兩個都是做 轉換值 的操作,區別就是入參的類型不是一樣的,map的入參是 Function<? super T, ? extends U> mapper 而 flatMap 入參則是 Function<? super T, Optional<U> > mapper 。

入參的不同也就導致瞭他們獲取返回值也是不同的,map中獲取的返回值自動被Optional包裝,flatMap中返回值保持不變,但必須是Optional類型。

這麼一看總是感覺不太對的樣子,我們去源碼裡面看看是什麼樣子的。

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


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

map 方法參數中的函數 mapper 輸出的是值,然後 map 方法會使用 Optional.ofNullable 將其包裝為 Optional;而 flatMap 要求參數中的函數 mapper 輸出的就是 Optional。

一個是比較聰明的,另外一個就相對來說不是那麼聰明瞭,人傢會自己包裝呀,是不是?

同樣的比較還有 orElse,orElseGet,orElseThrow 但是這個阿粉就不再給大傢絮叨瞭,因為上面的方法解釋上都很明顯的能看到瞭。

Lambda 表達式

Lambda 表達式實際上就是相當於是一個匿名內部類,他就是讓我們開發的人把函數當成參數傳遞給某個方法,然後把代碼當做數據去處理。

阿粉相信大傢肯定都瞭解這塊,就比如說下面的代碼對比:

Java7:

    List<String> stringList = Arrays.asList("1", "2", "3");
        for (String st:stringList) {
            System.out.println(st);
        }

Java8:

Arrays.asList("1", "2", "3").forEach((String st)->{
            System.out.println(st);
        });

同樣的一個循環,我們肯定想用第二種寫法不是麼?

va8:

Arrays.asList("1", "2", "3").forEach((String st)->{
            System.out.println(st);
        });

同樣的一個循環,我們肯定想用第二種寫法不是麼?

Java8 實際上在從發佈開始,很多公司都在用,但是也有很多人依舊選擇是 Java7,因為不想改變自己的學習風格,阿粉相信大傢如果是一個決心在開發領域一直做下去的人,那麼肯定會保持一個不斷學習的心,所以,你是這樣的人麼?

總結

到此這篇關於JDK8中Optional類巧用之判空的文章就介紹到這瞭,更多相關JDK8 Optional類判空內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: