<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java 8 一行代碼解決了空指針問題,太厲害了...

          共 12184字,需瀏覽 25分鐘

           ·

          2021-09-30 22:37

          在文章的開頭,先說下NPE問題,NPE問題就是,我們在開發(fā)中經(jīng)常碰到的NullPointerException.假設(shè)我們有兩個類,他們的UML類圖如下圖所示

          在這種情況下,有如下代碼

          user.getAddress().getProvince();

          這種寫法,在user為null時,是有可能報NullPointerException異常的。為了解決這個問題,于是采用下面的寫法

          if(user!=null){
              Address address = user.getAddress();
              if(address!=null){
                  String province = address.getProvince();
              }
          }

          這種寫法是比較丑陋的,為了避免上述丑陋的寫法,讓丑陋的設(shè)計變得優(yōu)雅。JAVA8提供了Optional類來優(yōu)化這種寫法,接下來的正文部分進(jìn)行詳細(xì)說明

          API介紹

          先介紹一下API,與其他文章不同的是,本文采取類比的方式來講,同時結(jié)合源碼。而不像其他文章一樣,一個個API羅列出來,讓人找不到重點。

          1、Optional(T value),empty(),of(T value),ofNullable(T value)

          這四個函數(shù)之間具有相關(guān)性,因此放在一組進(jìn)行記憶。

          先說明一下,Optional(T value),即構(gòu)造函數(shù),它是private權(quán)限的,不能由外部調(diào)用的。其余三個函數(shù)是public權(quán)限,供我們所調(diào)用。那么,Optional的本質(zhì),就是內(nèi)部儲存了一個真實的值,在構(gòu)造的時候,就直接判斷其值是否為空。好吧,這么說還是比較抽象。直接上Optional(T value)構(gòu)造函數(shù)的源碼,如下圖所示

          那么,**of(T value)**的源碼如下

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

          也就是說of(T value)函數(shù)內(nèi)部調(diào)用了構(gòu)造函數(shù)。根據(jù)構(gòu)造函數(shù)的源碼我們可以得出兩個結(jié)論:

          • 通過of(T value)函數(shù)所構(gòu)造出的Optional對象,當(dāng)Value值為空時,依然會報NullPointerException。
          • 通過of(T value)函數(shù)所構(gòu)造出的Optional對象,當(dāng)Value值不為空時,能正常構(gòu)造Optional對象。

          除此之外呢,Optional類內(nèi)部還維護(hù)一個value為null的對象,大概就是長下面這樣的

          public final class Optional<T> {
              //省略....
              private static final Optional<?> EMPTY = new Optional<>();
              private Optional() {
                  this.value = null;
              }
              //省略...
              public static<T> Optional<T> empty() {
                  @SuppressWarnings("unchecked")
                  Optional<T> t = (Optional<T>) EMPTY;
                  return t;
              }
          }

          那么,empty()的作用就是返回EMPTY對象。

          好了鋪墊了這么多,可以說ofNullable(T value)的作用了,上源碼

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

          好吧,大家應(yīng)該都看得懂什么意思了。相比較of(T value)的區(qū)別就是,當(dāng)value值為null時,of(T value)會報NullPointerException異常;ofNullable(T value)不會throw Exception,ofNullable(T value)直接返回一個EMPTY對象。

          那是不是意味著,我們在項目中只用ofNullable函數(shù)而不用of函數(shù)呢?

          不是的,一個東西存在那么自然有存在的價值。當(dāng)我們在運行過程中,不想隱藏NullPointerException。而是要立即報告,這種情況下就用Of函數(shù)。但是不得不承認(rèn),這樣的場景真的很少。博主也僅在寫junit測試用例中用到過此函數(shù)。另外關(guān)注:架構(gòu)師專欄,在后臺回復(fù):“面試題”可以獲取,高清PDF最新版3625頁互聯(lián)網(wǎng)大廠面試題。

          2、orElse(T other),orElseGet(Supplier<? extends T> other)和orElseThrow(Supplier<? extends X> exceptionSupplier)

          這三個函數(shù)放一組進(jìn)行記憶,都是在構(gòu)造函數(shù)傳入的value值為null時,進(jìn)行調(diào)用的。orElseorElseGet的用法如下所示,相當(dāng)于value值為null時,給予一個默認(rèn)值:

          @Test
          public void test() {
              User user = null;
              user = Optional.ofNullable(user).orElse(createUser());
              user = Optional.ofNullable(user).orElseGet(() -> createUser());
              
          }
          public User createUser(){
              User user = new User();
              user.setName("zhangsan");
              return user;
          }

          這兩個函數(shù)的區(qū)別:當(dāng)user值不為null時,orElse函數(shù)依然會執(zhí)行createUser()方法,而orElseGet函數(shù)并不會執(zhí)行createUser()方法,大家可自行測試。

          至于orElseThrow,就是value值為null時,直接拋一個異常出去,用法如下所示

          User user = null;
          Optional.ofNullable(user).orElseThrow(()->new Exception("用戶不存在"));

          3、map(Function<? super T, ? extends U> mapper)和flatMap(Function<? super T, Optional<U>> mapper)

          這兩個函數(shù)放在一組記憶,這兩個函數(shù)做的是轉(zhuǎn)換值的操作。

          直接上源碼

           public final class Optional<T> {
              //省略....
               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));
                  }
              }
              //省略...
               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));
                  }
              }
          }

          這兩個函數(shù),在函數(shù)體上沒什么區(qū)別。唯一區(qū)別的就是入?yún)ⅲ琺ap函數(shù)所接受的入?yún)㈩愋蜑?/span>Function<? super T, ? extends U>,而flapMap的入?yún)㈩愋蜑?/span>Function<? super T, Optional<U>>

          在具體用法上,對于map而言:

          如果User結(jié)構(gòu)是下面這樣的

          public class User {
              private String name;
              public String getName() {
                  return name;
              }
          }

          這時候取name的寫法如下所示

          String city = Optional.ofNullable(user).map(u-> u.getName()).get();

          對于flatMap而言:

          如果User結(jié)構(gòu)是下面這樣的

          public class User {
              private String name;
              public Optional<String> getName() {
                  return Optional.ofNullable(name);
              }
          }

          這時候取name的寫法如下所示

          String city = Optional.ofNullable(user).flatMap(u-> u.getName()).get();

          4、isPresent()和ifPresent(Consumer<? super T> consumer)

          這兩個函數(shù)放在一起記憶,isPresent即判斷value值是否為空,而ifPresent就是在value值不為空時,做一些操作。這兩個函數(shù)的源碼如下

          public final class Optional<T> {
              //省略....
              public boolean isPresent() {
                  return value != null;
              }
              //省略...
              public void ifPresent(Consumer<? super T> consumer) {
                  if (value != null)
                      consumer.accept(value);
              }
          }

          需要額外說明的是,大家千萬不要把

          if (user != null){
             // TODO: do something
          }

          給寫成

          User user = Optional.ofNullable(user);
          if (Optional.isPresent()){
             // TODO: do something
          }

          因為這樣寫,代碼結(jié)構(gòu)依然丑陋。博主會在后面給出正確寫法

          至于ifPresent(Consumer<? super T> consumer),用法也很簡單,如下所示

          Optional.ofNullable(user).ifPresent(u->{
              // TODO: do something
          });

          5、filter(Predicate<? super T> predicate)

          不多說,直接上源碼

          public final class Optional<T> {
              //省略....
             Objects.requireNonNull(predicate);
                  if (!isPresent())
                      return this;
                  else
                      return predicate.test(value) ? this : empty();
          }

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

          用法如下

          Optional<User> user1 = Optional.ofNullable(user).filter(u -> u.getName().length()<6);

          如上所示,如果user的name的長度是小于6的,則返回。如果是大于6的,則返回一個EMPTY對象。

          實戰(zhàn)使用

          例一

          在函數(shù)方法中

          以前寫法

          public String getCity(User user)  throws Exception{
                  if(user!=null){
                      if(user.getAddress()!=null){
                          Address address = user.getAddress();
                          if(address.getCity()!=null){
                              return address.getCity();
                          }
                      }
                  }
                  throw new Excpetion("取值錯誤"); 
              }

          JAVA8寫法

          public String getCity(User user) throws Exception{
              return Optional.ofNullable(user)
                             .map(u-> u.getAddress())
                             .map(a->a.getCity())
                             .orElseThrow(()->new Exception("取指錯誤"));
          }

          例二

          比如,在主程序中

          以前寫法

          if(user!=null){
              dosomething(user);
          }

          JAVA8寫法

           Optional.ofNullable(user)
              .ifPresent(u->{
                  dosomething(u);
          });

          例三

          以前寫法

          public User getUser(User user) throws Exception{
              if(user!=null){
                  String name = user.getName();
                  if("zhangsan".equals(name)){
                      return user;
                  }
              }else{
                  user = new User();
                  user.setName("zhangsan");
                  return user;
              }
          }

          java8寫法

          public User getUser(User user) {
              return Optional.ofNullable(user)
                             .filter(u->"zhangsan".equals(u.getName()))
                             .orElseGet(()-> {
                                  User user1 = new User();
                                  user1.setName("zhangsan");
                                  return user1;
                             });
          }

          其他的例子,不一一列舉了。不過采用這種鏈?zhǔn)骄幊蹋m然代碼優(yōu)雅了。但是,邏輯性沒那么明顯,可讀性有所降低,大家項目中看情況酌情使用。

          轉(zhuǎn)自:zjhred

          鏈接:https://sourl.cn/m9CXiF

          推薦閱讀:

          世界的真實格局分析,地球人類社會底層運行原理

          不是你需要中臺,而是一名合格的架構(gòu)師(附各大廠中臺建設(shè)PPT)

          企業(yè)IT技術(shù)架構(gòu)規(guī)劃方案

          論數(shù)字化轉(zhuǎn)型——轉(zhuǎn)什么,如何轉(zhuǎn)?

          華為干部與人才發(fā)展手冊(附PPT)

          企業(yè)10大管理流程圖,數(shù)字化轉(zhuǎn)型從業(yè)者必備!

          【中臺實踐】華為大數(shù)據(jù)中臺架構(gòu)分享.pdf

          華為的數(shù)字化轉(zhuǎn)型方法論

          華為如何實施數(shù)字化轉(zhuǎn)型(附PPT)

          超詳細(xì)280頁Docker實戰(zhàn)文檔!開放下載

          華為大數(shù)據(jù)解決方案(PPT)

          瀏覽 60
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产高清一级 | 国精产品一区一区三区四川 | 亚洲欧洲中文字幕 | 一本不卡免费特黄视频在线观看 | 日本熟妇50乱偷交尾 |