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

          JDK8已出這么久了,還是有很多人不會用Opitonal啊

          共 9338字,需瀏覽 19分鐘

           ·

          2022-07-13 22:50

            Java大聯(lián)盟

            致力于最高效的Java學習

          關(guān)注




          原文鏈接
          juejin.cn/post/6844904154075234318


          B 站搜索:楠哥教你學Java

          獲取更多優(yōu)質(zhì)視頻教程


          1、前言

          相信不少小伙伴已經(jīng)被java的NPE(Null Pointer Exception)所謂的空指針異常搞的頭昏腦漲,有大佬說過“防止 NPE,是程序員的基本修養(yǎng)?!钡切摒B(yǎng)歸修養(yǎng),也是我們程序員最頭疼的問題之一,那么我們今天就要盡可能的利用Java8的新特性Optional來盡量簡化代碼同時高效處理NPE(Null Pointer Exception空指針異常)

          2、認識Optional并使用

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

          常規(guī)判斷:

          //對象 人//屬性有 name,agePerson person=new Person();if (null==person){     return "person為null"; }return person;

          使用Optional:

          //對象 人//屬性有 name,agePerson person=new Person();return Optional.ofNullable(person).orElse("person為null");

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

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

          下面,我們就高效的學習一下神奇的Optional類!

          2.1 Optional對象創(chuàng)建

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

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

          再做一個簡單的實例展示 與上面對應(yīng)

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

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

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

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

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

          也就是如果value不為空則做返回,如果為空則拋出異常 "No value present" 簡單實例展示

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

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

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

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

          簡單的實例展示:

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

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

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

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

          看實例:

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

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

          2.5 Optional.filter()方法(過濾對象)

          filter()方法大致意思是,接受一個對象,然后對他進行條件過濾,如果條件符合則返回Optional對象本身,如果不符合則返回空Optional

          源碼:

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

          簡單實例:

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

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

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

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

          實例展示:

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

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

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

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

          實例:

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

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

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

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

          實例:

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

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

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

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

          實例:

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

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

          需要使用時supPerson.get()即可

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

          這個我個人在實戰(zhàn)中也經(jīng)常用到這個方法,方法作用的話就是如果為空,就拋出你定義的異常,如果不為空返回當前對象,在實戰(zhàn)中所有異??隙ㄊ且幚砗玫?,為了代碼的可讀性

          源碼:

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

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

          //簡單的一個查詢Member member = memberService.selectByPhone(request.getPhone());Optional.ofNullable(member).orElseThrow(() -> new ServiceException("沒有查詢的相關(guān)數(shù)據(jù)"));

          2.11 相似方法進行對比分析

          可能小伙伴看到這,沒用用過的話會覺得orElse()orElseGet()還有orElseThrow()很相似,map()flatMap()好相似

          哈哈哈不用著急,都是從這一步過來的,我再給大家總結(jié)一下不同方法的異同點

          orElse()和orElseGet()和orElseThrow()的異同點

          方法效果類似,如果對象不為空,則返回對象,如果為空,則返回方法體中的對應(yīng)參數(shù),所以可以看出這三個方法體中參數(shù)是不一樣的

          • orElse(T 對象)
          • orElseGet(Supplier < T >對象)
          • orElseThrow(異常)

          map()和orElseGet的異同點

          方法效果類似,對方法參數(shù)進行二次包裝,并返回,入?yún)⒉煌?/p>

          • map(function函數(shù))
          • flatmap(Optional< function >函數(shù))

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

          3、實戰(zhàn)場景再現(xiàn)

          場景1:在service層中 查詢一個對象,返回之后判斷是否為空并做處理

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

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

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

          然后在是Service中

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

          實戰(zhàn)場景還有很多,包括return時可以判斷是否返回當前值還是跳轉(zhuǎn)到另一個方法體中,什么的還有很多,如果大家沒有經(jīng)驗的小伙伴還想進行學習,可以評論一下我會回復大家

          4、Optional使用注意事項

          Optional真么好用,真的可以完全替代if判斷嗎?

          我想這肯定是大家使用完之后Optional之后可能會產(chǎn)生的想法,答案是否定的

          舉一個最簡單的栗子:

          例子1:

          如果我只想判斷對象的某一個變量是否為空并且做出判斷呢?

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

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

          5、jdk1.9對Optional優(yōu)化

          首先增加了三個方法:

          • or()ifPresentOrElse()stream()。
          • or()orElse等方法相似,如果對象不為空返回對象,如果為空則返回or()方法中預設(shè)的值。
          • ifPresentOrElse()方法有兩個參數(shù):一個 Consumer 和一個 Runnable。如果對象不為空,會執(zhí)行 Consumer 的動作,否則運行 Runnable。相比ifPresent()多了OrElse判斷。

          stream()將Optional轉(zhuǎn)換成stream,如果有值就返回包含值的stream,如果沒值,就返回空的stream。

          因為這個jdk1.9的Optional具體我沒有測試,同時也發(fā)現(xiàn)有蠻好的文章已經(jīng)也能讓大家明白jdk1.9的option的優(yōu)化,我就不深入去說了。


          楠哥簡介

          資深 Java 工程師,微信號 nnsouthwind

          《Java零基礎(chǔ)實戰(zhàn)》一書作者

          騰訊課程官方 Java 面試官今日頭條認證大V

          GitChat認證作者,B站認證UP主(楠哥教你學Java)

          致力于幫助萬千 Java 學習者持續(xù)成長。



          有收獲,就在看 
          瀏覽 37
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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>
                  综合狠狠操 | 91丨豆花丨成人熟女 熟女 | 一区二区三区中文字幕 | 俺来也俺去www色情网 | 麻豆果传媒成人A片免费看 |