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