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

          答應(yīng)我, 不要再用 if (obj != null) 判空了

          共 3034字,需瀏覽 7分鐘

           ·

          2022-04-11 11:52


          1. 前言

          相信不少小伙伴已經(jīng)被java的NPE(Null Pointer Exception)所謂的空指針異常搞的頭昏腦漲, 有大佬說(shuō)過(guò)“防止 NPE,是程序員的基本修養(yǎng)。”但是修養(yǎng)歸修養(yǎng),也是我們程序員最頭疼的問(wèn)題之一,那么我們今天就要盡可能的利用Java8的新特性 Optional來(lái)盡量簡(jiǎn)化代碼同時(shí)高效處理NPE(Null Pointer Exception 空指針異常)

          2. 認(rèn)識(shí)Optional并使用

          簡(jiǎn)單來(lái)說(shuō),Opitonal類(lèi)就是Java提供的為了解決大家平時(shí)判斷對(duì)象是否為空用 會(huì)用 null!=obj 這樣的方式存在的判斷,從而令人頭疼導(dǎo)致NPE(Null Pointer Exception 空指針異常),同時(shí)Optional的存在可以讓代碼更加簡(jiǎn)單,可讀性跟高,代碼寫(xiě)起來(lái)更高效.

          //常規(guī)判斷:
          ?????//對(duì)象?人
          ?????//屬性有?name,age
          ?????Person?person=new?Person();
          ?????if?(null==person){
          ?????????return?"person為null";
          ?????}
          ?????return?person;
          //使用Optional:
          ?????//對(duì)象?人
          ?????//屬性有?name,age
          ?????Person?person=new?Person();
          ?????return?Optional.ofNullable(person).orElse("person為null");

          測(cè)試展示類(lèi)Person代碼(如果有朋友不明白可以看一下這個(gè)):

          public?class?Person?{
          ????private?String?name;
          ????private?Integer?age;

          ????public?Person(String?name,?Integer?age)?{
          ????????this.name?=?name;
          ????????this.age?=?age;
          ????}

          ????public?Person()?{
          ????}

          ????public?String?getName()?{
          ????????return?name;
          ????}

          ????public?void?setName(String?name)?{
          ????????this.name?=?name;
          ????}

          ????public?Integer?getAge()?{
          ????????return?age;
          ????}

          ????public?void?setAge(Integer?age)?{
          ????????this.age?=?age;
          ????}
          }

          下面,我們就高效的學(xué)習(xí)一下神奇的Optional類(lèi)!

          2.1 Optional對(duì)象創(chuàng)建

          首先我們先打開(kāi)Optional的內(nèi)部,去一探究竟 先把幾個(gè)創(chuàng)建Optional對(duì)象的方法提取出來(lái)

          public?final?class?Optional<T>?{
          ???private?static?final?Optional?EMPTY?=?new?Optional<>();
          ???private?final?T?value;
          ???//我們可以看到兩個(gè)構(gòu)造方格都是private?私有的
          ???//說(shuō)明?我們沒(méi)辦法在外面去new出來(lái)Optional對(duì)象
          ???private?Optional()?{
          ????????this.value?=?null;
          ????}
          ???private?Optional(T?value)?{
          ????????this.value?=?Objects.requireNonNull(value);
          ????}
          ????//這個(gè)靜態(tài)方法大致?是創(chuàng)建出一個(gè)包裝值為空的一個(gè)對(duì)象因?yàn)闆](méi)有任何參數(shù)賦值
          ???public?static?Optional?empty()?{
          ????????@SuppressWarnings("unchecked")
          ????????Optional?t?=?(Optional)?EMPTY;
          ????????return?t;
          ????}
          ????//這個(gè)靜態(tài)方法大致?是創(chuàng)建出一個(gè)包裝值非空的一個(gè)對(duì)象?因?yàn)樽隽速x值
          ???public?static??Optional?of(T?value)?{
          ????????return?new?Optional<>(value);
          ????}
          ????//這個(gè)靜態(tài)方法大致是?如果參數(shù)value為空,則創(chuàng)建空對(duì)象,如果不為空,則創(chuàng)建有參對(duì)象
          ???public?static??Optional?ofNullable(T?value)?{
          ????????return?value?==?null???empty()?:?of(value);
          ????}
          ?}

          再做一個(gè)簡(jiǎn)單的實(shí)例展示 與上面對(duì)應(yīng)

          //?1、創(chuàng)建一個(gè)包裝對(duì)象值為空的Optional對(duì)象
          Optional?optEmpty?=?Optional.empty();
          //?2、創(chuàng)建包裝對(duì)象值非空的Optional對(duì)象
          Optional?optOf?=?Optional.of("optional");
          //?3、創(chuàng)建包裝對(duì)象值允許為空也可以不為空的Optional對(duì)象
          Optional?optOfNullable1?=?Optional.ofNullable(null);
          Optional?optOfNullable2?=?Optional.ofNullable("optional");

          我們關(guān)于創(chuàng)建Optional對(duì)象的內(nèi)部方法大致分析完畢 接下來(lái)也正式的進(jìn)入Optional的學(xué)習(xí)與使用中

          2.2 Optional.get()方法(返回對(duì)象的值)

          get()方法是返回一個(gè)option的實(shí)例值 源碼:

          public?T?get()?{
          ????if?(value?==?null)?{
          ????????throw?new?NoSuchElementException("No?value?present");
          ????}
          ????return?value;
          }

          也就是如果value不為空則做返回,如果為空則拋出異常 "No value present" 簡(jiǎn)單實(shí)例展示

          Person?person=new?Person();
          person.setAge(2);
          Optional.ofNullable(person).get();

          2.3 Optional.isPresent()方法(判讀是否為空)

          isPresent()方法就是會(huì)返回一個(gè)boolean類(lèi)型值,如果對(duì)象不為空則為真,如果為空則false 源碼:

          public?boolean?isPresent()?{
          ????return?value?!=?null;
          }

          簡(jiǎn)單的實(shí)例展示:

          Person?person=new?Person();
          person.setAge(2);
          if?(Optional.ofNullable(person).isPresent()){
          ????//寫(xiě)不為空的邏輯
          ????System.out.println("不為空");
          }else{
          ????//寫(xiě)為空的邏輯
          ????System.out.println("為空");
          }

          2.4 Optional.ifPresent()方法(判讀是否為空并返回函數(shù))

          這個(gè)意思是如果對(duì)象非空,則運(yùn)行函數(shù)體 源碼:

          public?void?ifPresent(Consumersuper?T>?consumer)?{
          ????//如果value不為空,則運(yùn)行accept方法體
          ????if?(value?!=?null)
          ????????consumer.accept(value);
          }

          看實(shí)例:

          Person?person=new?Person();
          person.setAge(2);
          Optional.ofNullable(person).ifPresent(p?->?System.out.println("年齡"+p.getAge()));

          如果對(duì)象不為空,則會(huì)打印這個(gè)年齡,因?yàn)閮?nèi)部已經(jīng)做了NPE(非空判斷),所以就不用擔(dān)心空指針異常了

          2.5 Optional.filter()方法(過(guò)濾對(duì)象)

          filter()方法大致意思是,接受一個(gè)對(duì)象,然后對(duì)他進(jìn)行條件過(guò)濾,如果條件符合則返回Optional對(duì)象本身,如果不符合則返回空Optional 源碼:

          public?Optional?filter(Predicatesuper?T>?predicate)?{
          ????Objects.requireNonNull(predicate);
          ????//如果為空直接返回this
          ????if?(!isPresent())
          ????????return?this;
          ????else
          ????????//判斷返回本身還是空Optional
          ????????return?predicate.test(value)???this?:?empty();
          }

          簡(jiǎn)單實(shí)例:

          Person?person=new?Person();
          person.setAge(2);
          Optional.ofNullable(person).filter(p?->?p.getAge()>50);

          2.6 Optional.map()方法(對(duì)象進(jìn)行二次包裝)

          map()方法將對(duì)應(yīng)Funcation函數(shù)式接口中的對(duì)象,進(jìn)行二次運(yùn)算,封裝成新的對(duì)象然后返回在Optional中 源碼:

          public?Optional?map(Functionsuper?T,???extends?U>?mapper)?{
          ????Objects.requireNonNull(mapper);
          ????//如果為空返回自己
          ????if?(!isPresent())
          ????????return?empty();
          ????else?{
          ????????//否則返回用方法修飾過(guò)的Optional
          ????????return?Optional.ofNullable(mapper.apply(value));
          ????}
          }

          實(shí)例展示:

          Person?person1=new?Person();
          person.setAge(2);
          String?optName?=?Optional.ofNullable(person).map(p?->?person.getName()).orElse("name為空");

          2.7 Optional.flatMap()方法(Optional對(duì)象進(jìn)行二次包裝)

          map()方法將對(duì)應(yīng)Optional< Funcation >函數(shù)式接口中的對(duì)象,進(jìn)行二次運(yùn)算,封裝成新的對(duì)象然后返回在Optional中 源碼:

          public?Optional?flatMap(Functionsuper?T,?Optional>?mapper)?{
          ????Objects.requireNonNull(mapper);
          ????if?(!isPresent())
          ????????return?empty();
          ????else?{
          ????????return?Objects.requireNonNull(mapper.apply(value));
          ????}
          }

          實(shí)例:

          Person?person=new?Person();
          person.setAge(2);
          Optional?optName?=?Optional.ofNullable(person).map(p?->?Optional.ofNullable(p.getName()).orElse("name為空"));

          2.8 Optional.orElse()方法(為空返回對(duì)象)

          常用方法之一,這個(gè)方法意思是如果包裝對(duì)象為空的話,就執(zhí)行orElse方法里的value,如果非空,則返回寫(xiě)入對(duì)象 源碼:

          public?T?orElse(T?other)?{
          ????//如果非空,返回value,如果為空,返回other
          ????return?value?!=?null???value?:?other;
          }

          實(shí)例:

          Person?person1=new?Person();
          person.setAge(2);
          Optional.ofNullable(person).orElse(new?Person("小明",?2));

          2.9 Optional.orElseGet()方法(為空返回Supplier對(duì)象)

          這個(gè)與orElse很相似,入?yún)⒉灰粯樱雲(yún)镾upplier對(duì)象,為空返回傳入對(duì)象的.get()方法,如果非空則返回當(dāng)前對(duì)象 源碼:

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

          實(shí)例:

          Optional>?sup=Optional.ofNullable(Person::new);
          //調(diào)用get()方法,此時(shí)才會(huì)調(diào)用對(duì)象的構(gòu)造方法,即獲得到真正對(duì)象
          Optional.ofNullable(person).orElseGet(sup.get());

          說(shuō)真的對(duì)于Supplier對(duì)象我也懵逼了一下,去網(wǎng)上簡(jiǎn)單查閱才得知 Supplier也是創(chuàng)建對(duì)象的一種方式,簡(jiǎn)單來(lái)說(shuō),Suppiler是一個(gè)接口,是類(lèi)似Spring的懶加載,聲明之后并不會(huì)占用內(nèi)存,只有執(zhí)行了get()方法之后,才會(huì)調(diào)用構(gòu)造方法創(chuàng)建出對(duì)象 創(chuàng)建對(duì)象的語(yǔ)法的話就是Supplier supPerson= Person::new; 需要使用時(shí)supPerson.get()即可

          2.10 Optional.orElseThrow()方法(為空返回異常)

          這個(gè)我個(gè)人在實(shí)戰(zhàn)中也經(jīng)常用到這個(gè)方法,方法作用的話就是如果為空,就拋出你定義的異常,如果不為空返回當(dāng)前對(duì)象,在實(shí)戰(zhàn)中所有異常肯定是要處理好的,為了代碼的可讀性 源碼:

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

          實(shí)例:這個(gè)就貼實(shí)戰(zhàn)源碼了

          //簡(jiǎn)單的一個(gè)查詢(xún)
          Member?member?=?memberService.selectByPhone(request.getPhone());
          Optional.ofNullable(member).orElseThrow(()?->?new?ServiceException("沒(méi)有查詢(xún)的相關(guān)數(shù)據(jù)"));

          2.11 相似方法進(jìn)行對(duì)比分析

          可能小伙伴看到這,沒(méi)用用過(guò)的話會(huì)覺(jué)得orElse()和orElseGet()還有orElseThrow()很相似,map()和flatMap()好相似 哈哈哈不用著急,都是從這一步過(guò)來(lái)的,我再給大家總結(jié)一下不同方法的異同點(diǎn) orElse()和orElseGet()和orElseThrow()的異同點(diǎn)

          方法效果類(lèi)似,如果對(duì)象不為空,則返回對(duì)象,如果為空,則返回方法體中的對(duì)應(yīng)參數(shù),所以可以看出這三個(gè)方法體中參數(shù)是不一樣的 orElse(T 對(duì)象) orElseGet(Supplier < T >對(duì)象) orElseThrow(異常)

          map()和orElseGet的異同點(diǎn)

          方法效果類(lèi)似,對(duì)方法參數(shù)進(jìn)行二次包裝,并返回,入?yún)⒉煌?map(function函數(shù)) flatmap(Optional< function >函數(shù))

          具體要怎么用,要根據(jù)業(yè)務(wù)場(chǎng)景以及代碼規(guī)范來(lái)定義,下面可以簡(jiǎn)單看一下我在實(shí)戰(zhàn)中怎用使用神奇的Optional

          3. 實(shí)戰(zhàn)場(chǎng)景再現(xiàn)

          場(chǎng)景1:在service層中 查詢(xún)一個(gè)對(duì)象,返回之后判斷是否為空并做處理

          //查詢(xún)一個(gè)對(duì)象
          Member?member?=?memberService.selectByIdNo(request.getCertificateNo());
          //使用ofNullable加orElseThrow做判斷和操作
          Optional.ofNullable(member).orElseThrow(()?->?new?ServiceException("沒(méi)有查詢(xún)的相關(guān)數(shù)據(jù)"));

          場(chǎng)景2:我們可以在dao接口層中定義返回值時(shí)就加上Optional 例如:我使用的是jpa,其他也同理

          public?interface?LocationRepository?extends?JpaRepository<Location,?String>?{
          Optional?findLocationById(String?id);
          }

          然在是Service中

          public?TerminalVO?findById(String?id)?{
          ????//這個(gè)方法在dao層也是用了Optional包裝了
          ????Optional?terminalOptional?=?terminalRepository.findById(id);
          ????//直接使用isPresent()判斷是否為空
          ????if?(terminalOptional.isPresent())?{
          ????//使用get()方法獲取對(duì)象值
          ????????Terminal?terminal?=?terminalOptional.get();
          ????????//在實(shí)戰(zhàn)中,我們已經(jīng)免去了用set去賦值的繁瑣,直接用BeanCopy去賦值
          ????????TerminalVO?terminalVO?=?BeanCopyUtils.copyBean(terminal,?TerminalVO.class);
          ????????//調(diào)用dao層方法返回包裝后的對(duì)象
          ????????Optional?location?=?locationRepository.findLocationById(terminal.getLocationId());
          ????????if?(location.isPresent())?{
          ????????????terminalVO.setFullName(location.get().getFullName());
          ????????}
          ????????return?terminalVO;
          ????}
          ????//不要忘記拋出異常
          ????throw?new?ServiceException("該終端不存在");
          }

          實(shí)戰(zhàn)場(chǎng)景還有很多,包括return時(shí)可以判斷是否返回當(dāng)前值還是跳轉(zhuǎn)到另一個(gè)方法體中,什么的還有很多,如果大家沒(méi)有經(jīng)驗(yàn)的小伙伴還想進(jìn)行學(xué)習(xí),可以評(píng)論一下我會(huì)回復(fù)大家

          4. Optional使用注意事項(xiàng)

          Optional真么好用,真的可以完全替代if判斷嗎? 我想這肯定是大家使用完之后Optional之后可能會(huì)產(chǎn)生的想法,答案是否定的 舉一個(gè)最簡(jiǎn)單的栗子:例子1:如果我只想判斷對(duì)象的某一個(gè)變量是否為空并且做出判斷呢?

          Person?person=new?Person();
          person.setName("");
          persion.setAge(2);
          //普通判斷
          if(StringUtils.isNotBlank(person.getName())){
          ???//名稱(chēng)不為空?qǐng)?zhí)行代碼塊
          }
          //使用Optional做判斷
          Optional.ofNullable(person).map(p?->?p.getName()).orElse("name為空");

          我覺(jué)得這個(gè)例子就能很好的說(shuō)明這個(gè)問(wèn)題,只是一個(gè)很簡(jiǎn)單判斷,如果用了Optional我們還需要考慮包裝值,考慮代碼書(shū)寫(xiě),考慮方法調(diào)用,雖然只有一行,但是可讀性并不好,如果別的程序員去讀,我覺(jué)得肯定沒(méi)有if看的明顯

          5. Jdk 9對(duì)Optional優(yōu)化

          首先增加了三個(gè)方法: or()、ifPresentOrElse() 和 stream()。 or() 與orElse等方法相似,如果對(duì)象不為空返回對(duì)象,如果為空則返回or()方法中預(yù)設(shè)的值。ifPresentOrElse() 方法有兩個(gè)參數(shù):一個(gè) Consumer 和一個(gè) Runnable。如果對(duì)象不為空,會(huì)執(zhí)行 Consumer 的動(dòng)作,否則運(yùn)行 Runnable。相比ifPresent()多了OrElse判斷。stream()將Optional轉(zhuǎn)換成stream,如果有值就返回包含值的stream,如果沒(méi)值,就返回空的stream。

          因?yàn)檫@個(gè)Jdk 9的Optional具體我沒(méi)有測(cè)試,同時(shí)也發(fā)現(xiàn)有蠻好的文章已經(jīng)也能讓大家明白Jdk 9的option的優(yōu)化,我就不深入去說(shuō)了。

          來(lái)源:juejin.cn/post/

          6844904154075234318


          ? ? ?

          1、IDEA 與 VsCode
          2、MyBatis 二級(jí)緩存 關(guān)聯(lián)刷新實(shí)現(xiàn)
          3、一個(gè)很酷的圖床系統(tǒng)(自帶鑒黃功能)
          4、用了 HTTPS 就一定安全嗎?
          5、60 個(gè)神級(jí) VS Code 插件!


          點(diǎn)分享

          點(diǎn)收藏

          點(diǎn)點(diǎn)贊

          點(diǎn)在看

          瀏覽 14
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                    国产伦精品一区二区三区最新章节 | 在线天堂av | 九九视频在线观看国产 | jlzz免费 | 欧美日逼图 |