日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

  1. <span id="fuzav"><listing id="fuzav"></listing></span>
          歡迎訪問 生活随笔!

          生活随笔

          當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

          java

          java中npe问题,【Java 8】巧用Optional之优雅规避NPE问题

          發(fā)布時(shí)間:2023/12/2 java 34 豆豆
          生活随笔 收集整理的這篇文章主要介紹了 java中npe问题,【Java 8】巧用Optional之优雅规避NPE问题 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

          避之不及的 NullPointerException

          NPE : NullPointerException

          空指針異常是最常見的Java異常之一,拋出NPE錯(cuò)誤不是用戶操作的錯(cuò)誤,而是開發(fā)人員的錯(cuò)誤,應(yīng)該被避免,那么只能在每個(gè)方法中加入非空檢查,閱讀性和維護(hù)性都比較差。

          以下是一個(gè)常見的嵌套對(duì)象:一個(gè)用戶所擁有的汽車,以及為這個(gè)汽車配備的保險(xiǎn)。

          public class User {

          private String userName;

          private Car car;

          public String getUserName() {

          return userName;

          }

          public void setUserName(String userName) {

          this.userName = userName;

          }

          public Car getCar() {

          return car;

          }

          public void setCar(Car car) {

          this.car = car;

          }

          }

          public class Car {

          private String carName;

          private Insurance insurance;

          public String getCarName() {

          return carName;

          }

          public void setCarName(String carName) {

          this.carName = carName;

          }

          public Insurance getInsurance() {

          return insurance;

          }

          public void setInsurance(Insurance insurance) {

          this.insurance = insurance;

          }

          }

          public class Insurance {

          private String insuranceName;

          public String getInsuranceName() {

          return insuranceName;

          }

          public void setInsuranceName(String insuranceName) {

          this.insuranceName = insuranceName;

          }

          }

          如果我們此時(shí),需要獲取一個(gè)用戶對(duì)應(yīng)的汽車保險(xiǎn)名稱,我們可能會(huì)寫出來以下的代碼

          private String getInsuranceName(User user) {

          return user.getCar().getInsurance().getInsuranceName();

          }

          顯然上面的程序是存在諸多NullPointerException隱患的,為了保證程序的健壯性,我們需要盡量避免出現(xiàn)空指針NullPointerException,那么通常我們會(huì)有以下兩種寫法。

          深層質(zhì)疑

          private String getInsuranceName(User user) {

          if (user != null) {

          Car car = user.getCar();

          if (car != null) {

          Insurance insurance = car.getInsurance();

          if (insurance != null) {

          return insurance.getInsuranceName();

          }

          }

          }

          return "not found";

          }

          及時(shí)退出

          private String getInsuranceName(User user) {

          if (user == null) {

          return "not found";

          }

          Car car = user.getCar();

          if (car == null) {

          return "not found";

          }

          Insurance insurance = car.getInsurance();

          if (insurance == null) {

          return "not found";

          }

          return insurance.getInsuranceName();

          }

          為了避免出現(xiàn)空指針,我們通常會(huì)采用以上兩種寫法,但是它們復(fù)雜又冗余,為了鼓勵(lì)程序員寫更干凈的代碼,代碼設(shè)計(jì)變得更加的優(yōu)雅。JAVA8提供了Optional類來優(yōu)化這種寫法。

          Optional

          Java 8中引入了一個(gè)新的類java.util.Optional。這是一個(gè)封裝Optional值的類。舉例來說,使用新的類意味著,如果你知道一個(gè)人可能有也可能沒有車,那么User類內(nèi)部的car變量就不應(yīng)該聲明為Car, 遇某人沒有車時(shí)把null引用值給它,而是應(yīng)該如下圖所示直接將其聲明為Optional類型。

          變量存在時(shí),Optional類只是對(duì)類簡(jiǎn)單封裝。變量不存在時(shí),缺失的值會(huì)被建模成一個(gè)“空” 的Optional對(duì)象,由方法Optional.empty()返回。它返回Optional類的特定單一實(shí)例。

          null引用和Optional.empty() 有什么本質(zhì)的區(qū)別嗎?

          從語(yǔ)義上,你可以把它們當(dāng)作一回事兒,但是實(shí)際中它們之間的差別非常大:如果你嘗試直接引用一個(gè)null,一定會(huì)觸發(fā)NullPointerException,不過使用 Optional.empty()就完全沒事兒,它是Optional類的一個(gè)有效對(duì)象。

          使用Optional而不是null的一個(gè)非常重要而又實(shí)際的語(yǔ)義區(qū)別是,第一個(gè)例子中,我們?cè)诼暶髯兞繒r(shí)使用的是Optional類型,而不是Car類型,這句聲明非常清楚地表明了這里發(fā)生變量缺失是允許的。與此相反,使用Car這樣的類型,可能將變量賦值為null,你只能依賴你對(duì)業(yè)務(wù)模型的理解,判斷一個(gè)null是否屬于該變量的有效值又或是異常情況。

          public class User {

          private String userName;

          private Optional car;

          public String getUserName() {

          return userName;

          }

          public Optional getCar() {

          return car;

          }

          }

          public class Car {

          private String carName;

          private Optional insurance;

          public String getCarName() {

          return carName;

          }

          public Optional getInsurance() {

          return insurance;

          }

          }

          public class Insurance {

          private String insuranceName;

          public String getInsuranceName() {

          return insuranceName;

          }

          }

          發(fā)現(xiàn)Optional是如何 富你模型的語(yǔ)義了吧。代碼中user引用的是Optional, 而car引用的是Optional,這種方式非常清晰地表達(dá)了你的模型中一個(gè)user 可能有也可能沒有car的情形,同樣,car可能進(jìn)行了保險(xiǎn),也可能沒有保險(xiǎn)。

          與此同時(shí),我們看到insurance的名稱insuranceName被聲明成String類型,而不是Optional ,這非常清楚地表明聲明為insurance的類中的名稱字段insuranceName是必須存在的。

          使用這種方式, 一旦通過引用insurance獲取insuranceName時(shí)發(fā)生NullPointerException,你就能非常確定地知道出錯(cuò)的原因,不再需要為其添加null的檢查查,因?yàn)閚ull的檢查查只會(huì)掩蓋問題,并未真正地修復(fù)問題。

          insurance必須有個(gè)名字,所以,如果你遇到一個(gè)insurance沒有名稱,你需要調(diào)查你的數(shù)據(jù)出了什么問題,而不應(yīng)該再添加一段代碼,將這個(gè)問題隱藏。

          Optional的方法介紹

          創(chuàng)建Optional

          of(T value)

          如果構(gòu)造參數(shù)是一個(gè)null,這段代碼會(huì)立即 出一個(gè)NullPointerException,而不是等到你 圖訪問car的屬性值時(shí)才返回一個(gè)錯(cuò)誤。

          public static Optional of(T value) {

          return new Optional<>(value);

          }

          ofNullable(T value)

          創(chuàng)建一個(gè)允許null值的Optional對(duì)象

          public static Optional ofNullable(T value) {

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

          }

          empty()

          創(chuàng)建一個(gè)空的Optional對(duì)象

          public static Optional empty() {

          Optional t = (Optional) EMPTY;

          return t;

          }

          常用方法get()是這些方法中最簡(jiǎn)單但又最不安全的方法。如果變量存在,它直接返回封裝的變量值,否則就拋出一個(gè)NoSuchElementException異常。所以,除非你非常確定Optional變量一定包含值,否則最好不要使用這個(gè)方法。

          orElse(T other),它允許你在 Optional對(duì)象不包含值時(shí)提供一個(gè)默認(rèn)值。

          orElseGet(Supplier extends T> other)是orElse方法的延遲調(diào)用版,Supplier方法只有在Optional對(duì)象不含值時(shí)才執(zhí)行調(diào)用。

          orElseThrow(Supplier extends X> exceptionSupplier)和get方法非常類似,它們?cè)庥鯫ptional對(duì)象為空時(shí)都會(huì)拋出一個(gè)異常,但是使用orElseThrow你可以定制希望拋出的異常類型。

          ifPresent(Consumer super T>)讓你能在變量值存在時(shí)執(zhí)行一個(gè)作為參數(shù)傳入的方法,否則就不進(jìn)行任何操作。

          注意:orElse(T other)和orElseGet(Supplier extends T> other)的區(qū)別

          這兩個(gè)函數(shù)的區(qū)別:當(dāng)value值不為null時(shí),orElse函數(shù)依然會(huì)執(zhí)行返回T的方法,而orElseGet函數(shù)并不會(huì)執(zhí)行返回T的方法。

          用map從Optional中提取和轉(zhuǎn)換值

          map(Function super T, ? extends U> mapper)

          可以把Optional對(duì)象看成一種特殊的集合數(shù)據(jù),它至多包含一個(gè)元素。如果Optional包含一個(gè)值,那函數(shù)就將該值作為參數(shù)傳遞給map,對(duì)該值進(jìn)行轉(zhuǎn)換。如果Optional為空,就什么也不做。

          String optionMap = Optional.ofNullable("abc").map(value -> value.toUpperCase()).get();

          使用flatMap鏈接Optional對(duì)象

          flatMap(Function super T, Optional> mapper)

          將兩層的optional合并為一個(gè)

          String optionFlatMap = Optional.ofNullable("abc").flatMap(value -> Optional.of((value + "flat-map").toUpperCase())).get();

          用filter剔除特定的值

          filter(Predicate super T> predicate)

          filter方法接受一個(gè)謂詞作為參數(shù)。如果Optional對(duì)象的值存在,并且它符合謂詞的條件, filter方法就返回其值;否則它就返回一個(gè)空的Optional對(duì)象。

          Optional filterOptional = Optional.ofNullable("abc").filter(value -> Objects.equals(value, "abc"));

          實(shí)戰(zhàn)

          嘗試獲取用戶的用戶名稱,不存在則返回默認(rèn)值

          String userName = Optional.ofNullable(userOfNull).orElse(new User()).getUserName();

          嘗試獲取用戶的carName,不存在則返回null

          String carName = Optional.ofNullable(userOfNull).map(u -> u.getCar()).map(c -> c.getCarName()).orElse(null);

          用戶名存在的時(shí)候轉(zhuǎn)為大寫

          Optional.ofNullable(user).map(u -> u.getUserName()).ifPresent(userName -> System.out.println(userName.toUpperCase()));

          過濾出來用戶名稱是張三的用戶

          Optional.ofNullable(user).filter(u -> Objects.equals(u.getUserName(),"張三")).map(u -> u.getUserName()).ifPresent(userName -> System.out.println(userName + "實(shí)戰(zhàn)Test"));

          將張三的用戶名稱更改為李四

          Optional.ofNullable(user).ifPresent(x -> {

          if (Objects.equals(user.getUserName(),"張三")){

          user.setUserName("李四");

          }

          });

          Optional.ofNullable(user).filter(u -> Objects.equals(user.getUserName(),"張三")).ifPresent(x -> user.setUserName("李四"));

          總結(jié)

          以上是生活随笔為你收集整理的java中npe问题,【Java 8】巧用Optional之优雅规避NPE问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

          如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。