Java中的Optional類用法詳細(xì)講解
前言
java中嘗試訪問空引用的屬性調(diào)用空引用的方法是會(huì)報(bào)空指針NullPointerException異常。實(shí)際項(xiàng)目中會(huì)處理大量為空的值,代碼會(huì)有很多的條件判斷,難以閱讀與維護(hù)。
if(user!=null){ System.out.println(user.getFullName()); }else { User defaultUser = new User("Stark", "Tony Stark"); System.out.println(defaultUser.getFullName()); }
一、Optional是什么?
Optional類引入了一種顯式的方式來處理可能為空的對(duì)象,強(qiáng)制程序員在可能為空的情況下進(jìn)行顯式的處理,以避免空指針異常。
Optional類似容器,可以包含各種類型的值,也可以為null。Optional類提供了一系列方法來方便地操作內(nèi)部的值。常用的方法有g(shù)et、orElse、orElseGet、orElseThrow等。
Optional的設(shè)計(jì)也考慮了函數(shù)式編程的原則,可以與Lambda表達(dá)式和StreamAPI等特性結(jié)合使用,可以進(jìn)行鏈?zhǔn)秸{(diào)用替代命令式編程的方式通過編寫if條件語句檢查null值。
二、Optional對(duì)象的方法
首先我們需要?jiǎng)?chuàng)建兩個(gè)類,User類與UserRepository類。
User類
import java.util.Optional; public class User { String name; String fullName; public User(String name, String fullName) { this.name = name; this.fullName = fullName; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getFullName() { return fullName; } public void setFullName(String fullName) { this.fullName = fullName; } }
UserRepository類
import java.util.Optional; public class UserRepository { public User findUserByName(String name){ if(name.equals("Peter")){ return new User("Peter","Peter Parker"); } else { return null; } } }
1.isPresent、isEmpty方法
isPresent方法用于檢查optional內(nèi)是否存在值,返回為布爾值,存在為true,不存在為false。
isEmpty方法用于檢查optional內(nèi)是否為空,返回為布爾值,為空為true,不為空為false。
//創(chuàng)建值為null的Optional對(duì)象 Optional<Object> optionalBox = Optional.empty(); System.out.println(optionalBox.isPresent()); System.out.println(optionalBox.isEmpty());
返回值為false與true。
2.empty、of、ofNullable方法
若創(chuàng)建的對(duì)象為null,則可以采用empty()方法。
Optional<Object> optionalBox = Optional.empty();
創(chuàng)建不為null的對(duì)象需要調(diào)用of方法,此時(shí)若value為null,則拋出NullPointerException異常。
String value = "Peter"; Optional<String> optionalBox = Optional.of(value);
若想要?jiǎng)?chuàng)建可能為null的對(duì)象,可以使用ofNullable( )方法。
String value = "Peter"; Optional<String> optionalBox = Optional.ofNullable(value);
3.get、orElse、orElseGet與orElseThrow方法
取值可以使用get()方法,若取值對(duì)象為null,會(huì)報(bào)java.util.NoSuchElementException異常(并非java.lang.NullPointerException異常)。
String value2 = optionalBox.get(); System.out.println(value2);
我們這里修改UserRepository類中的findUserByName方法,使其返回值為Optional對(duì)象。
public Optional<User> findUserByName(String name){ if(name.equals("Peter")){ return Optional.of(new User("Peter","Peter Parker")); } else { return Optional.empty(); } }
orElse是Optional類中的一個(gè)重要方法,它用于獲取值或在值為空的情況下提供一個(gè)默認(rèn)值。
UserRepository userRepository = new UserRepository(); Optional<User> optionalUser = userRepository.findUserByName("Peter2"); User user = optionalUser.orElse(new User("Stark","Tony Stark")); System.out.println(user.getFullName());
orElse方法即使讀到的數(shù)據(jù)不為null,仍會(huì)創(chuàng)建一個(gè)新User對(duì)象。因此最好使用只有讀到的數(shù)據(jù)為null的時(shí)候才會(huì)新建對(duì)象的orElseGet方法。
orElseGet方法的參數(shù)為Supplier的函數(shù)式接口,需要使用Lambda表達(dá)式實(shí)現(xiàn)。
optionalUser.orElseGet(()->new User("Stark","Tony Stark")); System.out.println(user.getFullName());
orElseThrow方法用于在 Optional 對(duì)象中的值為空時(shí)拋出一個(gè)指定的異常。
orElseThrow方法通過Supplier的函數(shù)式接口,可以生成自定義異常,默認(rèn)拋出異常為java.util.NoSuchElementException。
UserRepository userRepository = new UserRepository(); Optional<User> optionalUser = userRepository.findUserByName("Peter2"); optionalUser.orElseThrow(()->new RuntimeException("User not found"));
4.ifPresent、ifPresentOrElse、filter方法
ifPresent方法參數(shù)中若對(duì)象不為null,則會(huì)執(zhí)行Labmda中的方法;
若參數(shù)對(duì)象為null,則不會(huì)執(zhí)行Labmda中的方法,也不會(huì)報(bào)錯(cuò)。
UserRepository userRepository = new UserRepository(); Optional<User> optionalUser = userRepository.findUserByName("Peter2"); optionalUser.ifPresent(user -> System.out.println(user.getFullName()));
當(dāng)我們希望值為空時(shí)進(jìn)行其他操作,需要使用ifPresentOrElse方法。
optionalUser.ifPresentOrElse(user -> System.out.println(user.getFullName()), ()->System.out.println("User not found"));
若滿足filter方法中的條件,則會(huì)返回包含值的Optional對(duì)象,如果不滿足,則返回空的Optional對(duì)象
Optional<User> optionalUser2 = optionalUser.filter(user -> user.getFullName().equals("Peter Parker")); System.out.println(optionalUser2.isPresent());
5.Map與flatMap方法
進(jìn)行兩個(gè)方法前需要將User類中的 getFullName方法返回值修改為Optional。
public Optional<String> getFullName(){ return Optional.ofNullable(fullName); }
map方法:對(duì)Optional中的值進(jìn)行轉(zhuǎn)換(若值為空,則map方法什么也不會(huì)做,直接返回空的Optional對(duì)象)。
這個(gè)變換基于提供該map的函數(shù),并且這個(gè)變換是可選的,如果optional的值為空則不會(huì)做任何改變,并且map方法不會(huì)改變?cè)嫉腛ptional對(duì)象,而返回新的Optional對(duì)象,因此可以鏈?zhǔn)秸{(diào)用進(jìn)行多個(gè)轉(zhuǎn)換操作。
UserRepository userRepository = new UserRepository(); Optional<User> optionalUser = userRepository.findUserByName("Peter"); Optional<String> optionalFullName = optionalUser.map(User::getFullName); System.out.println(optionalFullName.get());
flatmap方法用于扁平化嵌套的Optional結(jié)構(gòu),以避免引入不必要的嵌套層級(jí),具體為flatmap的轉(zhuǎn)換函數(shù)返回的必須是另一個(gè)Optional對(duì)象,意味著flatMap方法可以用于嵌套的Optional情況,可以將兩個(gè)為嵌套關(guān)系的Optional對(duì)象轉(zhuǎn)換為一個(gè)。如果原始的Optional對(duì)象為空,或轉(zhuǎn)換函數(shù)返回的Optional對(duì)象為空,那么最終得到的也是為空的Optional對(duì)象。
UserRepository userRepository = new UserRepository(); Optional<User> optionalUser = userRepository.findUserByName("Peter"); Optional<String> optional = optionalUser.flatMap(User::getFullName);
若只需要對(duì)Optional對(duì)象中的值進(jìn)行轉(zhuǎn)換,而不需要嵌套的Optional,那么使用map方法更合適
如果要進(jìn)行一些操作返回另外一個(gè)Optional對(duì)象,flatmap方法更合適。
6.Stream方法
Optional的stream方法,可以將Optional對(duì)象轉(zhuǎn)換為Stream對(duì)象,對(duì)其中的值進(jìn)行流操作,如果Optional對(duì)象包含值,則將這個(gè)值封裝到一個(gè)Stream流中,如果Optional對(duì)象為空,則創(chuàng)造一個(gè)為空的Stream流
UserRepository userRepository = new UserRepository(); Optional<User> optionalUser = userRepository.findUserByName("Peter"); Stream<String> a =optionalUser.map(User::getName).stream(); a.forEach(System.out::println);
三、不適合使用Optional對(duì)象的情況
不應(yīng)該用于類的字段,會(huì)增加內(nèi)存消耗,并使序列化變得復(fù)雜;
不應(yīng)該用于方法參數(shù),使方法的理解和使用變得復(fù)雜;
不應(yīng)用于構(gòu)造器參數(shù),迫使調(diào)用者創(chuàng)建Optional實(shí)例,應(yīng)該通過構(gòu)造器重載解決;
不應(yīng)該用于集合的參數(shù),集合已經(jīng)很好的處理空集合的情況,沒必要使用Optional包裝集合;
不建議使用get方法,若為null會(huì)報(bào)錯(cuò)。
以下是如何處理和避免Java8 Optional錯(cuò)誤的一些建議:
在使用get()方法之前,一定要使用isPresent()方法檢查Optional對(duì)象是否存在。
不要使用isPresent()方法和orElse()方法。而應(yīng)該使用orElseGet()方法,讓程序只在需要時(shí)才執(zhí)行Supplier。
Optional<String> name = Optional.ofNullable(null); System.out.println("Name: " + name.orElseGet(() -> "Default Name"));
不要將Optional作為類的字段或方法的參數(shù)。這會(huì)導(dǎo)致類或方法變得混亂且難以維護(hù)。盡可能將Optional用于返回值,只在有需要時(shí)才將其用于參數(shù)。
避免在遞歸方法中使用Optional。在Java中遞歸是簡潔明了的,但在遞歸方法中使用Optional 會(huì)導(dǎo)致程序的性能大幅下降。
總結(jié)
以上就是今天要講的內(nèi)容,本文簡單介紹了Optional對(duì)象的使用以及不適合使用Optional對(duì)象的情況。
到此這篇關(guān)于Java中的Optional類用法的文章就介紹到這了,更多相關(guān)Java中Optional類內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于Java的打包jar、war、ear包的作用與區(qū)別詳解
本篇文章,小編為大家介紹,基于Java的打包jar、war、ear包的作用與區(qū)別詳解。需要的朋友參考下2013-04-04Maven的國內(nèi)鏡像(快速解決jar下載過慢的問題)
下面小編就為大家?guī)硪黄狹aven的國內(nèi)鏡像(快速解決jar下載過慢的問題)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-06-06Spring事物基礎(chǔ)知識(shí)及AOP相關(guān)陷阱分析
這篇文章主要介紹了Spring事物基礎(chǔ)知識(shí)及AOP相關(guān)陷阱,在平時(shí)的實(shí)際開發(fā)中經(jīng)常會(huì)遇到,只有深入了解了其中的原理,才會(huì)在工作中能夠有效應(yīng)對(duì)2021-09-09SpringBoot實(shí)現(xiàn)application配置信息加密
在配置文件中,我們有開發(fā)環(huán)境配置和生產(chǎn)環(huán)境配置,而生產(chǎn)環(huán)境的配置信息是需要做好防護(hù)的,避免外泄,所以本文為大家整理了application配置信息加密的方法,需要的可以參考下2023-07-07java正則表達(dá)式如何獲取xml文件中指定節(jié)點(diǎn)的值
這篇文章主要介紹了java正則表達(dá)式如何獲取xml文件中指定節(jié)點(diǎn)的值問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06SpringBoot監(jiān)控Tomcat活動(dòng)線程數(shù)來判斷是否完成請(qǐng)求處理方式
這篇文章主要介紹了SpringBoot監(jiān)控Tomcat活動(dòng)線程數(shù)來判斷是否完成請(qǐng)求處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02SpringBoot使用JUL實(shí)現(xiàn)日志記錄功能
在SpringBoot中,我們可以使用多種日志框架進(jìn)行日志記錄,其中,JUL(Java Util Logging)是Java平臺(tái)自帶的日志框架,它提供了簡單的 API 和配置,可以輕松地進(jìn)行日志記錄,本文將介紹如何在 SpringBoot中使用JUL進(jìn)行日志記錄,并提供示例代碼2023-06-06Java static方法用法實(shí)戰(zhàn)案例總結(jié)
這篇文章主要介紹了Java static方法用法,結(jié)合具體案例形式總結(jié)分析了java static方法功能、使用方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2019-09-09