Java8 Optional原理及用法解析
平時(shí)開發(fā)的工作中, 自己組內(nèi)的很多大佬經(jīng)常使用Optional的用法, 自己問他們, 這個(gè)到底有什么好處呢,他們說可以很好的規(guī)避好空指針的問題, 我們在平時(shí)寫java代碼的時(shí)候, 如果是一個(gè)新手, 肯定很多情況下都會出現(xiàn)空指針的報(bào)錯(cuò), 而java8 以后提供的Optional的問題, 就可以很好地規(guī)避我們空指針的問題.
空指針異常是導(dǎo)致Java應(yīng)用程序失敗的最常見原因。以前,為了解決空指針異常,Google公司著名的Guava項(xiàng)目引入了Optional類,Guava通過使用檢查空值的方式來防止代碼污染,它鼓勵(lì)程序員寫更干凈的代碼。受到Google Guava的啟發(fā),Optional類已經(jīng)成為Java 8類庫的一部分。Optional實(shí)際上是個(gè)容器:它可以保存類型T的值,或者僅僅保存null。Optional提供很多有用的方法,這樣我們就不用顯式進(jìn)行空值檢測。
1. 在Optional之前
在Java 8之前,程序員將返回null而不是Optional。這種方法有一些缺點(diǎn)。一種是沒有明確的方法來表示null可能是一個(gè)特殊值。相比之下,在API中返回Optional是明確的聲明,其中可能沒有值。如果我們要確保不會出現(xiàn)空指針異常,則需要對每個(gè)引用進(jìn)行顯式的空檢查,如下所示,我們都同意這是很多樣板。
// Life before Optional private void getIsoCode( User user){ if (user != null) { Address address = user.getAddress(); if (address != null) { Country country = address.getCountry(); if (country != null) { String isocode = country.getIsocode(); if (isocode != null) { isocode = isocode.toUpperCase(); } } } } }
為了簡化此過程,讓我們看一下如何使用Optional類,從創(chuàng)建和驗(yàn)證實(shí)例到使用它提供的不同方法并將其與返回相同類型的其他方法組合在一起,后者才是Optional的厲害之處。
Optional類提供了大約10種方法,我們可以使用它們來創(chuàng)建和使用Optional類,下面將介紹如何使用它們。
2. 創(chuàng)建一個(gè)Optional類
1. Optional.of()
// 參數(shù)不能是null
Optional<Integer> optional1 = Optional.of(1);
2. Optional.ofNullable()
Optional.of()或者Optional.ofNullable():創(chuàng)建Optional對象,差別在于of不允許參數(shù)是null,而ofNullable則無限制。
// 參數(shù)可以是null
Optional<Integer> optional2 = Optional.ofNullable(null);// 參數(shù)可以是非null
Optional<Integer> optional3 = Optional.ofNullable(2);
3. Optional.empty()
Optional.empty():所有null包裝成的Optional對象:
Optional<Integer> o1 = Optional.<Integer>empty()
Optional<Integer> o2 = Optional.ofNullable(null)
print(o1 == o2) // true
3. 判斷是否存在
1. isPresent()判斷值是否存在
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);// isPresent判斷值是否存在
System.out.println(optional1.isPresent() == true);
System.out.println(optional2.isPresent() == false);
2. ifPresent(Consumer consumer)
ifPresent(Consumer consumer), 如果Optional對象保存的值不是null, 則調(diào)用consumer對象,否則不調(diào)用
Optional<Integer> optional1 = Optional.ofNullable(1); Optional<Integer> optional2 = Optional.ofNullable(null); // 如果不是null,調(diào)用Consumer optional1.ifPresent(new Consumer<Integer>() { @Override public void accept(Integer t) { System.out.println("value is " + t); } }); // null,不調(diào)用Consumer optional2.ifPresent(new Consumer<Integer>() { @Override public void accept(Integer t) { System.out.println("value is " + t); } });
5. 獲取Optional里面的對象
1. get()
注意:在調(diào)用get()方法之前, 一定要先進(jìn)行isPresent()方法判斷是否存在值
//get Optional<String> optional1 = Optional.of("javaone"); if (optional1.isPresent()){ String value = optional1.get(); }
2. orElse(value)
返回值(如果存在);反之,返回其他。
//orElse
String nullName = null;
String name = Optional.ofNullable(nullName).orElse("default_name");
3. orElseGet(Supplier supplier)
返回值(如果存在);否則,調(diào)用other并返回該調(diào)用的結(jié)果。
該orElseGet() 方法類似于 orElse()。但是,如果沒有Optional值,則不采用返回值,而是采用供應(yīng)商功能接口,該接口將被調(diào)用并返回調(diào)用的值:
//orElseGet
String name = Optional.ofNullable(nullName).orElseGet(() -> "john");
那么,orElse() 和orElseGet()之間有什么區(qū)別。
乍一看,這兩種方法似乎具有相同的效果。但是,事實(shí)并非如此。讓我們創(chuàng)建一些示例,以突出兩者之間的相似性和行為差異。
首先,讓我們看看它們在對象為空時(shí)的行為:
String text = null; String defaultText = Optional.ofNullable(text).orElseGet(this::getDefaultValue); defaultText = Optional.ofNullable(text).orElse(getDefaultValue()); public String getDefaultValue() { System.out.println("Getting Default Value"); return "Default Value"; }
在上面的示例中,我們在Optional對象中包裝了一個(gè)空文本,然后嘗試使用兩種方法中的每一種來獲取包裝后的值。副作用如下:
Getting Default Value
Getting Default Value
在每種情況下都會調(diào)用默認(rèn)方法。碰巧的是,當(dāng)不存在包裝的值時(shí),兩者 orElse() 和的 orElseGet() 工作方式完全相同。
4. orElseThrow()
值不存在則拋出異常,存在則什么不做,有點(diǎn)類似Guava的Precoditions
Optional<Integer> optional1 = Optional.ofNullable(1); Optional<Integer> optional2 = Optional.ofNullable(null); optional1.orElseThrow(()->{throw new IllegalStateException();}); try { // 拋出異常 optional2.orElseThrow(()->{throw new IllegalStateException();}); } catch(IllegalStateException e ) { e.printStackTrace(); }
5. 流處理
1. filter(Predicate)
判斷Optional對象中保存的值是否滿足Predicate,并返回新的Optional。
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);Optional<Integer> filter1 = optional1.filter((a) -> a == null);
Optional<Integer> filter2 = optional1.filter((a) -> a == 1);
Optional<Integer> filter3 = optional2.filter((a) -> a == null);
System.out.println(filter1.isPresent());// false
System.out.println(filter2.isPresent());// true
System.out.println(filter2.get().intValue() == 1);// true
System.out.println(filter3.isPresent());// false
2. map(Function):
對Optional中保存的值進(jìn)行函數(shù)運(yùn)算,并返回新的Optional(可以是任何類型)
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);Optional<String> str1Optional = optional1.map((a) -> "key" + a);
Optional<String> str2Optional = optional2.map((a) -> "key" + a);System.out.println(str1Optional.get());// key1
System.out.println(str2Optional.isPresent());// false
3. flatMap()
功能與map()相似,差別請看如下代碼。flatMap方法與map方法類似,區(qū)別在于mapping函數(shù)的返回值不同。map方法的mapping函數(shù)返回值可以是任何類型T,而flatMap方法的mapping函數(shù)必須是Optional。
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Optional<String>> str1Optional = optional1.map((a) -> {
return Optional.<String>of("key" + a);
});Optional<String> str2Optional = optional1.flatMap((a) -> {
return Optional.<String>of("key" + a);
});System.out.println(str1Optional.get().get());// key1
System.out.println(str2Optional.get());// key1
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java數(shù)據(jù)結(jié)構(gòu)與算法之循環(huán)隊(duì)列的實(shí)現(xiàn)
循環(huán)隊(duì)列 (Circular Queue) 是一種特殊的隊(duì)列。循環(huán)隊(duì)列解決了隊(duì)列出隊(duì)時(shí)需要將所有數(shù)據(jù)前移一位的問題。本文將帶大家詳細(xì)了解循環(huán)隊(duì)列如何實(shí)現(xiàn),需要的朋友可以參考一下2021-12-12Spring的定時(shí)任務(wù)@Scheduled源碼詳解
這篇文章主要介紹了Spring的定時(shí)任務(wù)@Scheduled源碼詳解,@Scheduled注解是包org.springframework.scheduling.annotation中的一個(gè)注解,主要是用來開啟定時(shí)任務(wù),本文提供了部分實(shí)現(xiàn)代碼與思路,需要的朋友可以參考下2023-09-09springcloud微服務(wù)基于redis集群的單點(diǎn)登錄實(shí)現(xiàn)解析
這篇文章主要介紹了springcloud微服務(wù)基于redis集群的單點(diǎn)登錄實(shí)現(xiàn)解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09Java中的ReadWriteLock高效處理并發(fā)讀寫操作實(shí)例探究
這篇文章主要為大家介紹了Java中的ReadWriteLock高效處理并發(fā)讀寫操作實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01