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

          使用Java8中的Optional類(lèi)來(lái)消除代碼中的null檢查

          共 2210字,需瀏覽 5分鐘

           ·

          2020-08-20 17:23

          ? 作者:一書(shū)生VOID

          lw900925.github.io/java/java8-optional.html

          Optional類(lèi)是Java 8新增的一個(gè)類(lèi),用以解決程序中常見(jiàn)的NullPointerException異常問(wèn)題。本篇文章將詳細(xì)介紹Optional類(lèi),以及如何用它消除代碼中的null檢查。

          避免使用null檢查

          作為Java開(kāi)發(fā)人員,幾乎所有人都遇到過(guò)NullPointerException異常,大多數(shù)人遇到NullPointerException異常時(shí)都會(huì)在異常出現(xiàn)的地方加上if代碼塊來(lái)判斷值不為空,比如下面的代碼:

          public?void?bindUserToRole(User?user)?{
          ????if?(user?!=?null)?{
          ????????String?roleId?=?user.getRoleId();
          ????????if?(roleId?!=?null)?{
          ????????????Role?role?=?roleDao.findOne(roleId);
          ????????????if?(role?!=?null)?{
          ????????????????role.setUserId(user.getUserId());
          ????????????????roleDao.save(role);
          ????????????}
          ????????}
          ????}
          }

          這是比較普遍的做法,為了避免出現(xiàn)NullPointerException異常,手動(dòng)對(duì)可能為null值進(jìn)行了處理,不過(guò)代碼看起來(lái)非常糟糕,業(yè)務(wù)邏輯被淹沒(méi)在if邏輯判斷中,也許下面的代碼看起來(lái)可讀性稍好一些:

          public?String?bindUserToRole(User?user)?{
          ????if?(user?==?null)?{
          ????????return;
          ????}

          ????String?roleId?=?user.getRoleId();
          ????if?(roleId?==?null)?{
          ????????return;
          ????}

          ????Role?=?roleDao.findOne(roleId);
          ????if?(role?!=?null)?{
          ????????role.setUserId(user.getUserId());
          ????????roleDao.save(role);
          ????}
          }

          上面的代碼避免了深層的if語(yǔ)句嵌套,但本質(zhì)上是一樣的,方法內(nèi)有三個(gè)不同的返回點(diǎn),出錯(cuò)后調(diào)試也不容易,因?yàn)槟悴恢朗悄莻€(gè)值導(dǎo)致了NullPointerException異常。

          基于上面的原因,Java 8中引入了一個(gè)新的類(lèi)Optional,用以避免使用null值引發(fā)的種種問(wèn)題。擴(kuò)展:如何更優(yōu)雅的處理空值?

          Optional類(lèi)

          java.util.Optional類(lèi)是一個(gè)封裝了Optional值的容器對(duì)象,Optional值可以為null,如果值存在,調(diào)用isPresent()方法返回true,調(diào)用get()方法可以獲取值。

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

          Optional類(lèi)提供類(lèi)三個(gè)方法用于實(shí)例化一個(gè)Optional對(duì)象,它們分別為empty()、of()、ofNullable(),這三個(gè)方法都是靜態(tài)方法,可以直接調(diào)用。

          empty()方法用于創(chuàng)建一個(gè)沒(méi)有值的Optional對(duì)象:

          Optional?emptyOpt?=?Optional.empty();

          empty()方法創(chuàng)建的對(duì)象沒(méi)有值,如果對(duì)emptyOpt變量調(diào)用isPresent()方法會(huì)返回false,調(diào)用get()方法拋出NullPointerException異常。

          of()方法使用一個(gè)非空的值創(chuàng)建Optional對(duì)象:

          String?str?=?"Hello?World";
          Optional?notNullOpt?=?Optional.of(str);

          ofNullable()方法接收一個(gè)可以為null的值:

          Optional?nullableOpt?=?Optional.ofNullable(str);

          如果str的值為null,得到的nullableOpt是一個(gè)沒(méi)有值的Optional對(duì)象。

          提取Optional對(duì)象中的值

          如果我們要獲取User對(duì)象中的roleId屬性值,常見(jiàn)的方式是直接獲取:

          String?roleId?=?null;
          if?(user?!=?null)?{
          ????roleId?=?user.getRoleId();
          }

          使用Optional中提供的map()方法可以以更簡(jiǎn)單的方式實(shí)現(xiàn):

          Optional?userOpt?=?Optional.ofNullable(user);
          Optional?roleIdOpt?=?userOpt.map(User::getRoleId);

          使用orElse()方法獲取值

          Optional類(lèi)還包含其他方法用于獲取值,這些方法分別為:

          • orElse():如果有值就返回,否則返回一個(gè)給定的值作為默認(rèn)值;
          • orElseGet():與orElse()方法作用類(lèi)似,區(qū)別在于生成默認(rèn)值的方式不同。該方法接受一個(gè)Supplier函數(shù)式接口參數(shù),用于生成默認(rèn)值;
          • orElseThrow():與前面介紹的get()方法類(lèi)似,當(dāng)值為null時(shí)調(diào)用這兩個(gè)方法都會(huì)拋出NullPointerException異常,區(qū)別在于該方法可以指定拋出的異常類(lèi)型。

          下面來(lái)看看這三個(gè)方法的具體用法:

          String?str?=?"Hello?World";
          Optional?strOpt?=?Optional.of(str);
          String?orElseResult?=?strOpt.orElse("Hello?Shanghai");
          String?orElseGet?=?strOpt.orElseGet(()?->?"Hello?Shanghai");
          String?orElseThrow?=?strOpt.orElseThrow(
          ????????()?->?new?IllegalArgumentException("Argument?'str'?cannot?be?null?or?blank."));

          此外,Optional類(lèi)還提供了一個(gè)ifPresent()方法,該方法接收一個(gè)Consumer函數(shù)式接口,一般用于將信息打印到控制臺(tái):

          Optional?strOpt?=?Optional.of("Hello?World");
          strOpt.ifPresent(System.out::println);

          使用filter()方法過(guò)濾

          filter()方法可用于判斷Optional對(duì)象是否滿(mǎn)足給定條件,一般用于條件過(guò)濾:

          Optional?optional?=?Optional.of("[email protected]");
          optional?=?optional.filter(str?->?str.contains("164"));

          在上面的代碼中,如果filter()方法中的Lambda表達(dá)式成立,filter()方法會(huì)返回當(dāng)前Optional對(duì)象值,否則,返回一個(gè)值為空的Optional對(duì)象。Java知音公眾號(hào)內(nèi)回復(fù)“后端面試”,送你一份Java面試題寶典。

          如何正確使用Optional

          通過(guò)上面的例子可以看出,Optional類(lèi)可以?xún)?yōu)雅的避免NullPointerException帶來(lái)的各種問(wèn)題,不過(guò),你是否真正掌握了Optional的用法?

          假設(shè)你試圖使用Optional來(lái)避免可能出現(xiàn)的NullPointerException異常,編寫(xiě)了如下代碼:

          Optional?userOpt?=?Optional.ofNullable(user);
          if?(userOpt.isPresent())?{
          ????User?user?=?userOpt.get();
          ????//?do?something...
          }?else?{
          ????//?do?something...
          }

          坦白說(shuō),上面的代碼與我們之前的使用if語(yǔ)句判斷空值沒(méi)有任何區(qū)別,沒(méi)有起到Optional的正真作用:

          if?(user?!=?null)?{
          ????//?do?something...
          }?else?{
          ????//?do?something...
          }

          當(dāng)我們從之前版本切換到Java 8的時(shí)候,不應(yīng)該還按照之前的思維方式處理null值,Java 8提倡函數(shù)式編程,新增的許多API都可以用函數(shù)式編程表示,Optional類(lèi)也是其中之一。這里有幾條關(guān)于Optional使用的建議:

          • 盡量避免在程序中直接調(diào)用Optional對(duì)象的get()和isPresent()方法;
          • 避免使用Optional類(lèi)型聲明實(shí)體類(lèi)的屬性;

          第一條建議中直接調(diào)用get()方法是很危險(xiǎn)的做法,如果Optional的值為空,那么毫無(wú)疑問(wèn)會(huì)拋出NullPointerException異常,而為了調(diào)用get()方法而使用isPresent()方法作為空值檢查,這種做法與傳統(tǒng)的用if語(yǔ)句塊做空值檢查沒(méi)有任何區(qū)別。

          第二條建議避免使用Optional作為實(shí)體類(lèi)的屬性,它在設(shè)計(jì)的時(shí)候就沒(méi)有考慮過(guò)用來(lái)作為類(lèi)的屬性,如果你查看Optional的源代碼,你會(huì)發(fā)現(xiàn)它沒(méi)有實(shí)現(xiàn)java.io.Serializable接口,這在某些情況下是很重要的(比如你的項(xiàng)目中使用了某些序列化框架),使用了Optional作為實(shí)體類(lèi)的屬性,意味著他們不能被序列化。

          下面我們通過(guò)一些例子講解Optional的正確用法:

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

          上面提到創(chuàng)建Optional對(duì)象有三個(gè)方法,empty()方法比較簡(jiǎn)單,沒(méi)什么特別要說(shuō)明的。主要是of()和ofNullable()方法。當(dāng)你很確定一個(gè)對(duì)象不可能為null的時(shí)候,應(yīng)該使用of()方法,否則,盡可能使用ofNullable()方法,比如:

          public?static?void?method(Role?role)?{
          ????//?當(dāng)Optional的值通過(guò)常量獲得或者通過(guò)關(guān)鍵字new初始化,可以直接使用of()方法
          ????Optional?strOpt?=?Optional.of("Hello?World");
          ????Optional?userOpt?=?Optional.of(new?User());

          ????//?方法參數(shù)中role值不確定是否為null,使用ofNullable()方法創(chuàng)建
          ????Optional?roleOpt?=?Optional.ofNullable(role);
          }

          orElse()方法的使用

          return?str?!=?null???str?:?"Hello?World"

          上面的代碼表示判斷字符串str是否為空,不為空就返回,否則,返回一個(gè)常量。使用Optional類(lèi)可以表示為:

          return?strOpt.orElse("Hello?World")

          簡(jiǎn)化if-else

          User?user?=?...
          if?(user?!=?null)?{
          ????String?userName?=?user.getUserName();
          ????if?(userName?!=?null)?{
          ????????return?userName.toUpperCase();
          ????}?else?{
          ????????return?null;
          ????}
          }?else?{
          ????return?null;
          }

          上面的代碼可以簡(jiǎn)化成:

          User?user?=?...
          Optional?userOpt?=?Optional.ofNullable(user);

          return?userOpt.map(User::getUserName)
          ????????????.map(String::toUpperCase)
          ????????????.orElse(null);

          總結(jié)一下,新的Optional類(lèi)讓我們可以以函數(shù)式編程的方式處理null值,拋棄了Java 8之前需要嵌套大量if-else代碼塊,使代碼可讀性有了很大的提高。

          瀏覽 52
          點(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>
                  乱伦激情 | 亚洲视频x| 国产精品视频免费在线观看 | 色婷婷五月天网站 | 18禁黄免费 |