<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>

          求求你,不要再使用!=null判空了!

          共 5642字,需瀏覽 12分鐘

           ·

          2020-10-16 09:19

          △Hollis, 一個對Coding有著獨特追求的人△
          作者 l?上帝愛吃蘋果
          來源 l Hollis(ID:hollischuang)
          本文來自作者投稿,原作者:上帝愛吃蘋果
          對于Java程序員來說,null是令人頭痛的東西。時常會受到空指針異常(NPE)的騷擾。連Java的發(fā)明者都承認這是他的一項巨大失誤。
          那么,有什么辦法可以避免在代碼中寫大量的判空語句呢?
          有人說可以使用 JDK8提供的 Optional 來避免判空,但是用起來還是有些麻煩。
          作者在日常工作中,封裝了一個工具,可以可以鏈式調(diào)用對象成員而無需判空,相比原有的if null邏輯 和 JDK8提供的 Optional 更加優(yōu)雅易用,在工程實踐中大大提高了編碼效率,也讓代碼更加的精準和優(yōu)雅。



          不優(yōu)雅的判空調(diào)用
          我想從事Java開發(fā)的小伙伴肯定有遇到過下面這種讓人難受的判空邏輯:現(xiàn)在有一個User類,School 是它的成員變量

          /**

          *?@author?Axin

          *?@since?2020-09-20

          *?@summary?一個User類定義

          ?*?(Ps:Data 是lombok組件提供的注解,簡化了get set等等的約定代碼)

          */


          @Data

          public?class?User?{

          ????private?String?name;

          ????private?String?gender;

          ????private?School?school;

          ????@Data

          ????public?static?class?School?{

          ????????private?String?scName;

          ????????private?String?adress;

          ????}

          }

          現(xiàn)在想要獲得School的成員變量 adress , 一般的處理方式:

          public?static?void?main(String[]?args)?{

          ????User?axin?=?new?User();

          ????User.School?school?=?new?User.School();

          ????axin.setName("hello");

          ????if?(Objects.nonNull(axin)?&&?Objects.nonNull(axin.getSchool()))?{

          ????????User.School?userSc?=?axin.getSchool();

          ????????System.out.println(userSc.getAdress());

          ????}

          }

          獲取adress時要對School進行判空,雖然有些麻煩,到也能用,通過 JDK8 提供的 Optional 工具也是可以,但還是有些麻煩。
          而下文的 OptionalBean 提供一種可以鏈式不斷地調(diào)用成員變量而無需判空的方法,直接鏈式調(diào)用到你想要獲取的目標變量,而無需擔心空指針的問題。



          鏈式調(diào)用成員變量
          如果用了本文設(shè)計的工具 OptionalBean ,那么上述的調(diào)用可以簡化成這樣:

          public?static?void?main(String[]?args)?{

          ????User?axin?=?new?User();

          ????User.School?school?=?new?User.School();

          ????axin.setName("hello");

          ????//?1.?基本調(diào)用

          ????String?value1?=?OptionalBean.ofNullable(axin)

          ????????????.getBean(User::getSchool)

          ????????????.getBean(User.School::getAdress).get();

          ????System.out.println(value1);

          }

          執(zhí)行結(jié)果:
          其中User的school變量為空,可以看到代碼并沒有空指針,而是返回了null。這個工具怎么實現(xiàn)的呢?



          OptionalBean 工具

          /**

          *?@author?Axin

          *?@since?2020-09-10

          *?@summary?鏈式調(diào)用?bean?中?value?的方法

          */


          public?final?class?OptionalBean<T>?{

          ????
          private?static?final?OptionalBean<?>?EMPTY?=?new?OptionalBean<>();

          ????
          private?final?T?value;

          ????
          private?OptionalBean()?{

          ????????
          this.value?=?null;

          ????}

          ????
          /**

          ?????*?空值會拋出空指針

          ?????*?@param?value

          ?????*/


          ????
          private?OptionalBean(T?value)?{

          ????????
          this.value?=?Objects.requireNonNull(value);

          ????}

          ????
          /**

          ?????*?包裝一個不能為空的?bean

          ?????*?@param?value

          ?????*?@param?<T>
          ?????*?@return

          ?????*/


          ????
          public?static?<T>?OptionalBean<T>?of(T?value)?{

          ????????
          return?new?OptionalBean<>;(value);

          ????}

          ????
          /**

          ?????*?包裝一個可能為空的?bean

          ?????*?@param?value

          ?????*?@param?<T>?????*?@return

          ?????*/


          ????
          public?static?<T>?OptionalBean<T>?ofNullable(T?value)?{

          ????????
          return?value?==?null???empty()?:?of(value);

          ????}

          ????
          /**

          ?????*?取出具體的值

          ?????*?@param?fn

          ?????*?@param?<R>?????*?@return

          ?????*/


          ????
          public?T?get()?{

          ????????
          return?Objects.isNull(value)???null?:?value;

          ????}

          ????
          /**

          ?????*?取出一個可能為空的對象

          ?????*?@param?fn

          ?????*?@param?<R>?????*?@return

          ?????*/


          ????
          public?<R>?OptionalBean<R>?getBean(Function<??super?T,???extends?R>?fn)?{

          ????????
          return?Objects.isNull(value)???OptionalBean.empty()?:?OptionalBean.ofNullable(fn.apply(value));

          ????}

          ????
          /**

          ?????*?如果目標值為空?獲取一個默認值

          ?????*?@param?other

          ?????*?@return

          ?????*/


          ????
          public?T?orElse(T?other)?{

          ????????
          return?value?!=?null???value?:?other;

          ????}

          ????
          /**

          ?????*?如果目標值為空?通過lambda表達式獲取一個值

          ?????*?@param?other

          ?????*?@return

          ?????*/


          ????
          public?T?orElseGet(Supplier<??extends?T>?other)?{

          ????????
          return?value?!=?null???value?:?other.get();

          ????}

          ????
          /**

          ?????*?如果目標值為空?拋出一個異常

          ?????*?@param?exceptionSupplier

          ?????*?@param?<X>?????*?@return

          ?????*?@throws?X

          ?????*/


          ????
          public?<X?extends?Throwable>;?T?orElseThrow(Supplier<??extends?X>?exceptionSupplier)?throws?X?{

          ????????
          if?(value?!=?null)?{

          ????????????
          return?value;

          ????????}?
          else?{

          ????????????
          throw?exceptionSupplier.get();

          ????????}

          ????}

          ????
          public?boolean?isPresent()?{

          ????????
          return?value?!=?null;

          ????}

          ????
          public?void?ifPresent(Consumer<??super?T>?consumer)?{

          ????????
          if?(value?!=?null)

          ????????????consumer.accept(value);

          ????}

          ????
          @Override

          ????
          public?int?hashCode()?{

          ????????
          return?Objects.hashCode(value);

          ????}

          ????
          /**

          ?????*?空值常量

          ?????*?@param?<T>?????*?@return

          ?????*/


          ????
          public?static <T>?OptionalBean<T>?empty()?{

          ????????
          @SuppressWarnings("unchecked")

          ????????OptionalBean<T>?none?=?(OptionalBean<T>)?EMPTY;

          ????????
          return?none;

          ????}

          }

          工具設(shè)計主要參考了 Optional 的實現(xiàn),再加上對鏈式調(diào)用的擴展就是上述的OptionalBean。
          getBean 其實是當變量為空時返回了一個 包裝空值的 OptionalBean 對象,同時泛型的使用讓工具更加易用。



          使用手冊
          可以看到代碼中也提供了和 Optional 一樣的擴展方法,如 ifPresent()、orElse()等等:

          public?static?void?main(String[]?args)?{

          ????User?axin?=?new?User();

          ????User.School?school?=?new?User.School();

          ????axin.setName("hello");

          ????//?1.?基本調(diào)用

          ????String?value1?=?OptionalBean.ofNullable(axin)

          ????????????.getBean(User::getSchool)

          ????????????.getBean(User.School::getAdress).get();

          ????System.out.println(value1);

          ????//?2.?擴展的?isPresent方法?用法與?Optional?一樣

          ????boolean?present?=?OptionalBean.ofNullable(axin)

          ????????????.getBean(User::getSchool)

          ????????????.getBean(User.School::getAdress).isPresent();

          ????System.out.println(present);

          ????//?3.?擴展的?ifPresent?方法

          ????OptionalBean.ofNullable(axin)

          ????????????.getBean(User::getSchool)

          ????????????.getBean(User.School::getAdress)

          ????????????.ifPresent(adress?->?System.out.println(String.format("地址存在:%s",?adress)));

          ????//?4.?擴展的?orElse

          ????String?value2?=?OptionalBean.ofNullable(axin)

          ????????????.getBean(User::getSchool)

          ????????????.getBean(User.School::getAdress).orElse("家里蹲");

          ????System.out.println(value2);

          ????//?5.?擴展的?orElseThrow

          ????try?{

          ????????String?value3?=?OptionalBean.ofNullable(axin)

          ????????????????.getBean(User::getSchool)

          ????????????????.getBean(User.School::getAdress).orElseThrow(()?->?new?RuntimeException("空指針了"));

          ????}?catch?(Exception?e)?{

          ????????System.out.println(e.getMessage());

          ????}

          }

          run一下:



          總結(jié)
          設(shè)計了一種可以鏈式調(diào)用對象成員而無需判空的工具讓代碼更加的精準和優(yōu)雅,如果本文設(shè)計的工具滿足了剛好解決你的困擾,那就在項目中使用吧!
          如果您有更的設(shè)計或者文中有錯誤,還請留言一起討論,互相進步!


          推薦閱讀:


          喜歡我可以給我設(shè)為星標哦

          好文章,我“在看”
          瀏覽 59
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  囯产精品宾馆在线精品酒店 | 乱伦免费视频中文字幕 | 亚洲黄色电影大全 | 欧美性受XXXX黑人XYX性爽冫 | 可以看的免费黄色电影 |