成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

正確使用Java8中的Optional,它遠比我們想象的優(yōu)秀

開發(fā) 前端
怎樣做才能避免不期而至的NullPointerException?通常,在需要的地方添加null的檢查,所以我們的代碼多了很多的判斷是否為null的驗證,影響代碼結構,甚至有時不加思索是否需要驗證也會統(tǒng)一加上非空判斷,來避免不可預知的空值,防止生產環(huán)境造成損失!

前言

我常說學習一定要有目的,首先發(fā)現(xiàn)問題,或者不便之處,然后尋找解決方案,解決方案可能有很多,我們要選擇好的方法來使用

這篇文章介紹JDK8推出的Optional容器,會從以下幾點展開:

  • 現(xiàn)在編程的問題或者說痛點是什么
  • 通過案例演示:解決方案有哪些,Optional怎么解決
  • Optional系統(tǒng)用法
  • Optional的錯誤用法
  • Optional總結

由此一起來認識Optional的正確使用方式,遠比我們想象的強大,好用,看很多文章和教程都在講API,個人感覺調用一個方法誰不會?它到底好在哪才是最重要的,我發(fā)布的文章都秉承發(fā)現(xiàn)問題,解決問題的理念展開,好了,不吹了,精彩的要來了!

編程痛點

作為Java程序員遇到NullPointerException是非常痛苦的,這可能是我們遇到的最多的異常了

前后端聯(lián)調:嗨!哥們,你這500啥意思呀?

后端:先是沉思,這怎么會有空指針?對前端說:哥們等1分鐘,馬上解決,我可不能說空指針,我可是老開發(fā)了!說空指針多沒面子。

產生過這種無奈的請在評論區(qū)大聲說出來!無論是新手還是專家,在NullPointerException面前可謂眾生平等

我們編程時經常承受:寫了類型檢查,值判斷,最終沒想到竟然是一個null的痛苦,毫不留情的甩出來一個令人厭煩的NullPointerException,比如:

系統(tǒng)中用戶,有些用戶進行了實名認證,擁有身份證信息,有些用戶并沒有完成實名認證就沒有身份證信息【不要深究設計是否合理,僅僅是舉例講解Optional知識點】

用戶類:

public class User {

private Long id;

private String name;
// 身份證對象
private IdCard idCard;
// getter、setter、toString
}

身份證類:

public class IdCard {
private Long id;
// 身份證號碼
private String idNum;
// getter、setter、toString
}

測試類:獲取用戶的身份證號碼

public class OptionalMain {

public static void main(String[] args) {
// 創(chuàng)建用戶對象
User user = new User();
// 調用一系列get方法獲取身份證號碼
// 因為調用 getIdCard()時并沒有身份證對象為null,再調用getIdNum方法則出現(xiàn) NullPointerException
String idNum = user.getIdCard().getIdNum();
System.out.println(idNum);
}
}

運行結果:

如果user是傳遞進來的,傳進來的user也有可能是null

解決方案

怎樣做才能避免不期而至的NullPointerException?通常,在需要的地方添加null的檢查,所以我們的代碼多了很多的判斷是否為null的驗證,影響代碼結構,甚至有時不加思索是否需要驗證也會統(tǒng)一加上非空判斷,來避免不可預知的空值,防止生產環(huán)境造成損失!并且添加的方式往往各有不同:

嵌套判斷:

public class OptionalMain {
public static void main(String[] args) {
User user = new User();
// 判斷user是否為null
if(user != null) {
IdCard idCard = user.getIdCard();
// 判斷 idCard 是否為null
if(idCard != null) {
// 獲取身份證號碼
System.out.println(idCard.getIdNum());
}else {
System.out.println("未實名認證!");
}
}else {
System.out.println("該用戶不存在!");
}
}
}

逐個判斷:

public class OptionalMain {

/**
* 獲取身份證號碼
* @param user:用戶
* @return:身份證號碼
*/
public static String getUserIdcardNum(User user) {
// 判斷用戶是否為空
if(user == null) {
return "無此用戶";
}
// 判斷是否實名認證
if(user.getIdCard() == null) {
return "該用戶未實名認證";
}
// 返回身份證號碼,如果:要對身份證號碼進行操作,也要對idNum進行非空判斷
return user.getIdCard().getIdNum();
}

public static void main(String[] args) {
// 創(chuàng)建用戶對象
User user = new User();
// 1、調用獲取身份證方法,有用戶但未實名
System.out.println("******未認證******");
String userIdcardNum1 = getUserIdcardNum(user);
System.out.println("結果:" + userIdcardNum1);
// 2、傳遞空用戶
System.out.println("******空用戶******");
String userIdcardNum2 = getUserIdcardNum(null);
System.out.println("結果:" + userIdcardNum2);
// 3、創(chuàng)建身份證對象
IdCard idCard = new IdCard();
idCard.setId(1L);
idCard.setIdNum("411481199611111516");
user.setIdCard(idCard);
// 傳遞實名認證的用戶
System.out.println("******已認證******");
String userIdcardNum3 = getUserIdcardNum(user);
System.out.println("結果:" + userIdcardNum3);
}
}

運行結果:

如果有其他要求,就要做更多的非空判斷,影響代碼的連貫性,凈判斷空值了

一旦忘記判斷某一個值是否為空,就又要和 NullPointerException 偶遇了,它并不是女朋友,而是最不想遇見的【債主】

null值帶來的問題

  • NullPointerException是目前Java程序開發(fā)中最典型的異常,有些書中稱其為錯誤之源,個人覺得有點夸張,你覺著呢?
  • 各種非空判斷,讓代碼變的冗余,閱讀性很糟糕,非空判斷對業(yè)務實現(xiàn)是毫無意義的
  • null值本身也毫無意義,可以認為是給對象一個【錯誤的默認值】
  • null可以被賦值給任意的引用數(shù)據(jù)類型,如果是分布式系統(tǒng),該值被傳遞到另一個服務中,無法知道最初的它是什么類型,也無法對其進行賦值
  • Java為了簡化語言,摒棄了指針的概念,但是 NullPointerException是個例外

Optional的出現(xiàn)

Java團隊結合Haskell和Scala語言對null值的處理方式,在JDK8時推出Optional類來專門處理空值問題,當然該類并不是為了避免我們去寫!=null的非空判斷,他功能很強,配合Lambda表達式更香

源碼注釋

/**
* A container object which may or may not contain a non-null value.
一個可以包含或不包含非空值的容器對象
* If a value is present, {@code isPresent()} will return {@code true} and
* {@code get()} will return the value.
如果存在值,isPresent()方法會返回true,通過get()方法返回值
*
* <p>Additional methods that depend on the presence or absence of a contained
* value are provided, such as {@link #orElse(java.lang.Object) orElse()}
* (return a default value if value not present) and
* {@link #ifPresent(java.util.function.Consumer) ifPresent()} (execute a block
* of code if the value is present).
提供了取決于是否存在包含值的其他方法,比如orElse,如果值不存在,則返回默認值 并且 可以通過ifPresent()
判斷值是否存在,存在則執(zhí)行代碼塊
* <p>This is a <a href="../lang/doc-files/ValueBased.html">value-based</a>
* class; use of identity-sensitive operations (including reference equality
* ({@code ==}), identity hash code, or synchronization) on instances of
* {@code Optional} may have unpredictable results and should be avoided.
這是一個基于值的類,應避免使用于身份敏感操作【這里應該意思是:對象是否存在不確定的敏感操作】(包括引用 ==,哈希或同步)的實例可能會產生不可預測的結果
* @since

從Optional類的定義和聲明來看特點如下:

  • 是一個final類,不可被繼承,并且是一個泛型類
  • 該類是一個容器,可以用來存儲對象
  • 該類提供了一系列方法來判斷是否有值【isPresent()】和獲取值【get()】

Optional解決null問題

通過案例感受Optional處理null的套路:

  • 將可能為null,或者說允許為null的數(shù)據(jù)存儲進Optional容器中
  • 通過Optional的map、filter、flatMap方法對數(shù)據(jù)進行處理,獲取需要的對象屬性,用法和Stream相同
  • 如果數(shù)據(jù)為空了,可以返回一個自定義對象,或者拋出異常都可以,隨你所愿

User類:

public class User {

private Long id;

private String name;

// 將可能為null的對象放入Optional中
private Optional<IdCard> idCard;

// getter、setter、toString
}

IdCard類:

public class IdCard {
private Long id;
// 如果身份證號碼也允許為null,也可以放入Optional中【Optional<String>
// 但是實名認證了,身份證號碼就是必須的了不是嗎,
// 一旦使用了Optional,沒有身份證號碼時,也不會出現(xiàn)報錯,可能會出現(xiàn)數(shù)據(jù)錯誤,所以也不要濫用
private String idNum;
// getter、setter、toString
}

測試類:

public class OptionalMain {

/**
* 獲取身份證號碼
* @param user:用戶
* @return:身份證號碼
*/
public static String getUserIdcardNum(User user){
// 將User通過Optional.of() 方法 存儲進Optional
Optional<User> optionalUser = Optional.of(user);
// 通過map方法先獲取user中身份對象,orElse:如果沒有,返回一個自定義的Optional<IdCard>對象
Optional<IdCard> optionalIdCard = optionalUser.map(User::getIdCard).orElse(Optional.of(new IdCard()));
// 通過map方法獲取IdCard中的idNum,如果沒有返回 "無實名認證"字符串
String idNum = optionalIdCard.map(IdCard::getIdNum).orElse("無實名認證");
return idNum;
}

public static void main(String[] args){
User user = new User();
// 將user對象傳進方法中,該對象中的IdCard為null
System.out.println(getUserIdcardNum(user));
}
}

運行結果:

我們僅僅傳入了user對象,IdCard為null,通過getUserIdcardNum方法處理之后,返回定義的無實名認證,這里并沒有做if...else的判斷,這樣的代碼看起來更優(yōu)雅,不是嗎?

總結來說:

  • 把對象放進Optional中,可以通過Optional提供的API來操作容器中的對象
  • 如:對象非空正常使用,我們可以通過get()方法獲取對象
  • 如果是空可以通過某些方法【orElse、orElseGet、orElseThrow】,返回自定義的結果,避免空指針異常出現(xiàn)
  • 通過一些判斷方法來判斷Optional中對象是否為null

接下來講解一下Optional中的API,系統(tǒng)認識,學習強大的Optional

Optional結構

Optional方法概覽

方法

作用

Optional.empty()

創(chuàng)建一個空的 Optional 實例

Optional.of(T t)

創(chuàng)建一個 Optional 實例,當 t為null時拋出異常

Optional.ofNullable(T t)

創(chuàng)建一個 Optional 實例,但當 t為null時不會拋出異常,而是返回一個空的實例

get()

獲取optional實例中的對象,當optional 容器為空時報錯

isPresent()

判斷optional是否為空,如果空則返回false,否則返回true

ifPresent(Consumer c)

如果optional不為空,則將optional中的對象傳給Comsumer函數(shù)

orElse(T other)

如果optional不為空,則返回optional中的對象;如果為null,則返回 other 這個默認值

orElseGet(Supplier<T> other)

如果optional不為空,則返回optional中的對象;如果為null,則使用Supplier函數(shù)生成默認值other

orElseThrow(Supplier<X> exception)

如果optional不為空,則返回optional中的對象;如果為null,則拋出Supplier函數(shù)生成的異常

filter(Predicate<T> p)

如果optional不為空,則執(zhí)行斷言函數(shù)p,如果p的結果為true,則返回原本的optional,否則返回空的optional

map(Function<T, U> mapper)

如果optional不為空,則將optional中的對象 t 映射成另外一個對象 u,并將 u 存放到一個新的optional容器中

flatMap(Function< T,Optional<U>> mapper)

跟上面一樣,在optional不為空的情況下,將對象t映射成另外一個optional,區(qū)別在于:map會自動將u放到optional中,而flatMap則需要手動給u創(chuàng)建一個optional

強烈建議:打開編輯器,多翻閱源碼,對學習和編碼都有很大幫助,剛開始看不懂沒關系,量變產生質變

Optional 創(chuàng)建

通過Optional源碼發(fā)現(xiàn):

  • 該類final修飾,不能被繼承,只有一個Object父類
  • 是一個泛型類,使用時為了類型安全指明泛型類型
  • 連個私有常量,供內部調用,其中value為Optional容器中存儲的對象
  • 兩個構造方法,無參和有參的都為私有,說明不能通過構造方法創(chuàng)建Optional對象,需要通過內部提供的【empty()、of(T t)、ofNullable(T t)】三個靜態(tài)方法創(chuàng)建,這種創(chuàng)建方式其實就是【工廠模式】


代碼實現(xiàn):

// 創(chuàng)建一個包裝對象值為空的Optional對象
Optional<Object> optional1 = Optional.empty();

// 創(chuàng)建包裝對象值非空的Optional對象,如果傳入null則出現(xiàn)`NullPointerException`
Optional<String> optional2 = Optional.of("optional");

// 創(chuàng)建包裝對象值允許為空的Optional對象
Optional<Object> optional3 = Optional.ofNullable(null);

Optional其他API

get()

作用:獲取optional實例中的對象,當optional 容器為空時報錯

源碼:

  • 判斷value是否為null
  • 為null,拋出 NoSuchElementException("No value present")異常
  • 不為null,返回value

null值Optional:

// 創(chuàng)建值為null的Optional對象
Optional<String> optional = Optional.empty();
// get返回 NoSuchElementException("No value present")
String result = optional.get();
System.out.println(result);

非null值Optional:

// 創(chuàng)建值為:optional的Optional對象
Optional<String> optional = Optional.of("optional");
// 返回值 optional
String result = optional.get();
System.out.println(result);

isPresent()

作用:判斷optional是否為空,如果空則返回false,否則返回true

源碼:

代碼實現(xiàn):

List<String> users = new ArrayList<>();
users.add("柯南");
users.add("佩奇");
users.add("喜洋洋");
Optional<List<String>> optional = Optional.of(users);
// 判斷并消費
optional.ifPresent(System.out::println);

orElse(T other)

作用:如果optional不為空,則返回optional中的對象;如果為null,則返回 other 這個默認值

源碼:

代碼實現(xiàn):

User user = new User(1L,"格雷福斯");
// 1、存儲非null數(shù)據(jù)
Optional<User> userOptional = Optional.ofNullable(user);
// 獲取用戶名
String name1 = userOptional.orElse(new User(0L, "帥氣添甄")).getName();
// 非null,結果為:格雷福斯
System.out.println(name1);

// 2、存儲null數(shù)據(jù)
Optional<User> nullOptional = Optional.ofNullable(null);
String name2 = nullOptional.orElse(new User(0L, "帥氣添甄")).getName();
// 為null,結果:帥氣添甄
System.out.println(name2);

orElseGet(Supplierother)

作用:如果optional不為空,則返回optional中的對象;如果為null,則使用Supplier函數(shù)生成默認值other

源碼:

代碼實現(xiàn):

User user = new User(1L,"格雷福斯");
Optional<User> userOptional = Optional.ofNullable(user);
// 為null直接返回`Supplier`生產型函數(shù)接口返回的對象
String name = userOptional.orElseGet(() new User(0L, "添甄")).getName();
System.out.println(name);

orElseThrow(Supplierexception)

作用:如果optional不為空,則返回optional中的對象;如果為null,則拋出Supplier函數(shù)生成的異常

源碼:

代碼實現(xiàn):

User user = new User(1L,"格雷福斯");
Optional<User> userOptional = Optional.ofNullable(user);
// 為null直接返回`Supplier`生產型函數(shù)接口返回的對象
String name = userOptional.orElseGet(() new User(0L, "添甄")).getName();
System.out.println(name);

orElseThrow(Supplierexception)

作用:如果optional不為空,則返回optional中的對象;如果為null,則拋出Supplier函數(shù)生成的異常

源碼:

代碼實現(xiàn):

User user = new User(1L,"格雷福斯");
Optional<User> userOptional = Optional.ofNullable(user);
// 如果數(shù)據(jù)為null,拋出 指定異常
String name = userOptional.orElseThrow(() new RuntimeException("無數(shù)據(jù)")).getName();
System.out.println(name);

filter(Predicatep)

作用:如果optional不為空,則執(zhí)行斷言函數(shù)p,如果p的結果為true,則返回原本的optional,否則返回空的optional

源碼:

代碼實現(xiàn):

User user = new User(1L,"格雷福斯");
Optional<User> userOptional = Optional.ofNullable(user);

// 過濾名字長度大于3,如果有值才輸出,沒值就不輸出
userOptional.filter(item -> item.getName().length() > 3).ifPresent(System.out::println);

map(Function mapper)

作用:如果optional不為空,則將optional中的對象 t 映射成另外一個對象 u,并將 u 存放到一個新的optional容器中,該方法與Stream的map作用一樣

源碼:

代碼實現(xiàn):

User user = new User(1L,"格雷福斯");
Optional<User> userOptional = Optional.ofNullable(user);

// 只獲取用戶名
String name = userOptional.map(User::getName).orElse("添甄");
System.out.println(name);

flatMap(Function< T,Optional> mapper)

作用:在optional不為空的情況下,將對象t映射成另外一個optional,17-flatMapmap接收的是U類型,而flatMap接收的是Optional<U>類型,返回也是需要放進Optional中

源碼:

代碼實現(xiàn):

User user = new User(1L,"格雷福斯");
Optional<User> userOptional = Optional.ofNullable(null);
Optional<String> optional = userOptional.flatMap(item -> Optional.ofNullable(item.getName()));
String name = optional.orElse("添甄");
System.out.println(name);

錯誤示范

獲取用戶名:

User user = new User(1L,"格雷福斯");
Optional<User> userOptional = Optional.ofNullable(user);
// 判斷是否有值
if (userOptional.isPresent()) {
String name = userOptional.get().getName();
System.out.println(name);
}else {
System.out.println("無值");
}

通過調用isPresent方法判斷是否有值,這還是增加了判斷,破壞代碼結構

正確姿勢:

多用map,orElse,filter方法發(fā)揮Optional的作用

User user = new User(1L,"格雷福斯");
Optional<User> userOptional = Optional.ofNullable(user);
String name = userOptional.map(User::getName).orElse("無值");
System.out.println(name);

總結

  • Optional是一個用來解決null值,避免發(fā)生空指針異常的容器,配合Lambda表達式寫出優(yōu)雅代碼
  • 靜態(tài)工廠方法Optional.empty()、Optional.of()以及Optional.ofNullable()創(chuàng)建Optional對象
  • Optional類包含多種方法,其中map、flatMap、filter,它們在概念上與Stream類中對應的方法十分相似
  • 使用Optional能幫助你開發(fā)出更便于閱讀和簡介的程序
  • 多使用Optional中的方法給定默認值,比如map、orElse等方法來避免過多的if判斷

文章出自:??石添的編程哲學??,如有轉載本文請聯(lián)系【石添的編程哲學】今日頭條號。

責任編輯:武曉燕 來源: 今日頭條
相關推薦

2017-10-31 20:45:07

JavaJava8Optional

2019-05-21 06:34:53

暗網網絡攻擊網絡安全

2022-04-12 14:59:45

加密貨幣比特幣環(huán)保

2021-09-05 23:54:55

人工智能機器語言

2025-02-25 08:36:56

2022-10-08 08:16:32

數(shù)據(jù)庫Oracle數(shù)據(jù)

2021-01-04 08:39:26

JAVA8OptionalNPE

2013-08-20 10:26:34

加密安全

2021-02-18 16:06:43

JavaStream代碼

2017-09-23 15:28:32

JavaOptional方法

2022-03-28 18:10:40

微服務架構

2023-03-26 19:58:25

ChatGPT技術架構

2025-06-26 08:10:00

Java8函數(shù)

2014-04-11 12:49:00

Java8Java8教程

2022-08-11 16:37:10

DeepMindAI人工智能

2022-07-20 16:39:37

AI數(shù)據(jù)

2010-01-18 10:27:20

2014-08-21 09:30:09

2024-01-17 08:20:20

AI人工智能AGI

2024-01-31 08:53:01

Java數(shù)組代碼
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产精品免费一区二区三区四区 | 久国久产久精永久网页 | 男人午夜视频 | 国际精品鲁一鲁一区二区小说 | 午夜视频一区二区三区 | 免费在线成人网 | 欧美激情久久久 | 亚洲天堂久久新 | 国产女人精品视频 | 成人h电影在线观看 | 免费av直接看 | 日韩在线播放视频 | 国产精品久久久久久久久图文区 | www网站在线观看 | 国产在线精品一区二区 | 男人的天堂在线视频 | 色综合欧美 | 国产精品免费一区二区三区四区 | 国产精品日韩在线观看一区二区 | 天天射色综合 | 成人免费一区二区三区视频网站 | 中文字幕在线一区 | 全免一级毛片 | 亚洲国产一区二区三区在线观看 | 精品一区在线看 | 国产一区二区自拍 | 成人综合视频在线观看 | 黄色大片网站 | 国产日韩欧美91 | 天天干免费视频 | 久久99久久| 国内精品免费久久久久软件老师 | 成人免费淫片aa视频免费 | 国产高清精品一区二区三区 | 国产99精品 | 在线欧美亚洲 | 免费视频99| 激情久久av一区av二区av三区 | 69av网| 国产欧美一区二区三区在线看蜜臀 | 成人国产精品免费观看视频 |