日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
正確使用Java8中的Optional,它遠比我們想象的優(yōu)秀

前言

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

10多年的多倫網(wǎng)站建設(shè)經(jīng)驗,針對設(shè)計、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時及時工作處理。營銷型網(wǎng)站建設(shè)的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整多倫建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計,從而大程度地提升瀏覽體驗。創(chuàng)新互聯(lián)建站從事“多倫網(wǎng)站設(shè)計”,“多倫網(wǎng)站推廣”以來,每個客戶項目都認真落實執(zhí)行。

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

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

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

編程痛點

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

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

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

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

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

系統(tǒng)中用戶,有些用戶進行了實名認證,擁有身份證信息,有些用戶并沒有完成實名認證就沒有身份證信息【不要深究設(shè)計是否合理,僅僅是舉例講解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();
// 調(diào)用一系列g(shù)et方法獲取身份證號碼
// 因為調(diào)用 getIdCard()時并沒有身份證對象為null,再調(diào)用getIdNum方法則出現(xiàn) NullPointerException
String idNum = user.getIdCard().getIdNum();
System.out.println(idNum);
}
}

運行結(jié)果:

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

解決方案

怎樣做才能避免不期而至的NullPointerException?通常,在需要的地方添加null的檢查,所以我們的代碼多了很多的判斷是否為null的驗證,影響代碼結(jié)構(gòu),甚至有時不加思索是否需要驗證也會統(tǒng)一加上非空判斷,來避免不可預(yù)知的空值,防止生產(chǎn)環(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、調(diào)用獲取身份證方法,有用戶但未實名
System.out.println("******未認證******");
String userIdcardNum1 = getUserIdcardNum(user);
System.out.println("結(jié)果:" + userIdcardNum1);
// 2、傳遞空用戶
System.out.println("******空用戶******");
String userIdcardNum2 = getUserIdcardNum(null);
System.out.println("結(jié)果:" + 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("結(jié)果:" + userIdcardNum3);
}
}

運行結(jié)果:

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

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

null值帶來的問題

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

Optional的出現(xiàn)

Java團隊結(jié)合Haskell和Scala語言對null值的處理方式,在JDK8時推出Optional類來專門處理空值問題,當然該類并不是為了避免我們?nèi)?=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()方法返回值
*
*

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í)行代碼塊
*

This is a value-based
* 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.
這是一個基于值的類,應(yīng)避免使用于身份敏感操作【這里應(yīng)該意思是:對象是否存在不確定的敏感操作】(包括引用 ==,哈?;蛲剑┑膶嵗赡軙a(chǎn)生不可預(yù)測的結(jié)果
* @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;

// getter、setter、toString
}

IdCard類:

public class IdCard {
private Long id;
// 如果身份證號碼也允許為null,也可以放入Optional中【Optional
// 但是實名認證了,身份證號碼就是必須的了不是嗎,
// 一旦使用了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 optionalUser = Optional.of(user);
// 通過map方法先獲取user中身份對象,orElse:如果沒有,返回一個自定義的Optional對象
Optional 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));
}
}

運行結(jié)果:

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

總結(jié)來說:

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

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

Optional結(jié)構(gòu)

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

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

orElseThrow(Supplier exception)

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

filter(Predicate p)

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

map(Function mapper)

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

flatMap(Function< T,Optional> mapper)

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

強烈建議:打開編輯器,多翻閱源碼,對學(xué)習(xí)和編碼都有很大幫助,剛開始看不懂沒關(guān)系,量變產(chǎn)生質(zhì)變

Optional 創(chuàng)建

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

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

代碼實現(xiàn):

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

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

// 創(chuàng)建包裝對象值允許為空的Optional對象
Optional 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 optional = Optional.empty();
// get返回 NoSuchElementException("No value present")
String result = optional.get();
System.out.println(result);

非null值Optional:

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

isPresent()

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

源碼:

代碼實現(xiàn):

List users = new ArrayList<>();
users.add("柯南");
users.add("佩奇");
users.add("喜洋洋");
Optional> 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 userOptional = Optional.ofNullable(user);
// 獲取用戶名
String name1 = userOptional.orElse(new User(0L, "帥氣添甄")).getName();
// 非null,結(jié)果為:格雷福斯
System.out.println(name1);

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

orElseGet(Supplierother)

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

源碼:

代碼實現(xiàn):

User user = new User(1L,"格雷福斯");
Optional userOptional = Optional.ofNullable(user);
// 為null直接返回`Supplier`生產(chǎn)型函數(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 userOptional = Optional.ofNullable(user);
// 為null直接返回`Supplier`生產(chǎn)型函數(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 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的結(jié)果為true,則返回原本的optional,否則返回空的optional

源碼:

代碼實現(xiàn):

User user = new User(1L,"格雷福斯");
Optional 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 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類型,返回也是需要放進Optional中

源碼:

代碼實現(xiàn):

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

錯誤示范

獲取用戶名:

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

通過調(diào)用isPresent方法判斷是否有值,這還是增加了判斷,破壞代碼結(jié)構(gòu)

正確姿勢:

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

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

總結(jié)

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

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


標題名稱:正確使用Java8中的Optional,它遠比我們想象的優(yōu)秀
文章來源:http://www.5511xx.com/article/cocoioj.html