淺談Java8的特性之Optional類
一、Optional類 簡(jiǎn)介
Optional類是 Java 8 引入的一個(gè)很有趣的特性。它主要解決的問題是臭名昭著的空指針異常(NullPointerException)
- Optional 類是一個(gè)可以為null的容器對(duì)象。如果值存在則isPresent()方法會(huì)返回true,調(diào)用get()方法會(huì)返回該對(duì)象。
- Optional 是個(gè)容器:它可以保存類型T的值,或者僅僅保存null。Optional提供很多有用的方法,這樣我們就不用顯式進(jìn)行空值檢測(cè)。
- Optional 類的引入很好的解決空指針異常。
Optional 是一個(gè)對(duì)象容器,具有以下兩個(gè)特點(diǎn):
- 提示用戶要注意該對(duì)象有可能為null
- 簡(jiǎn)化if else代碼
舉一個(gè)簡(jiǎn)單的例子,在 Java 8 之前,任何訪問對(duì)象方法或?qū)傩缘恼{(diào)用都可能導(dǎo)致 NullPointerException:
用戶 -> 家庭住址 -> 城市 ->郵編 String postCode = user.getAddress().getCity().getPostCode();
在這個(gè)示例中,為了避免異常,就得在訪問每一個(gè)值之前對(duì)其進(jìn)行明確地檢查:
if (user != null) {
Address address = user.getAddress();
if (address != null) {
City city= address.getCity();
if (city != null) {
String postCode = city.getPostCode();
if (postCode != null) {
//對(duì)postCode進(jìn)行操作
test(postCode);
}
}
}
}這很容易就變得冗長,難以維護(hù)。 為了簡(jiǎn)化這個(gè)過程,我們就可以用 Optional 類。
二、Optional類的使用
1. 創(chuàng)建:
Optional類的實(shí)例創(chuàng)建有三種方式:
- Optional.empty() :創(chuàng)建一個(gè)空的 Optional 實(shí)例。
- Optional.of(T t) :創(chuàng)建一個(gè) Optional 實(shí)例,當(dāng) t為null時(shí)拋出異常(NullPointerException)。
- Optional.ofNullable(T t) :創(chuàng)建一個(gè) Optional 實(shí)例,但當(dāng) t為null時(shí)不會(huì)拋出異常,而是返回一個(gè)空的實(shí)例。
2. 獲?。?/h3>
- get():獲取optional實(shí)例中的對(duì)象,當(dāng)optional 容器為空時(shí)報(bào)錯(cuò)。
3. 判斷:
- isPresent():判斷optional是否為空,如果空則返回false,否則返回true
- ifPresent(Consumer c):如果optional不為空,則將optional中的對(duì)象傳給Comsumer函數(shù)
public class OptionalDemo {
public static void main(String[] args) {
User user = new User("王也", "5");
User userNull= null;
Optional<User> optional = Optional.ofNullable(user);
System.out.println(optional.isPresent());
optional.ifPresent(u -> System.out.println("optional不為null "+u));
}
}
- orElse(T other):如果optional不為空,則返回optional中的對(duì)象;如果為null,則返回 other 這個(gè)默認(rèn)值
User user = new User("王也", "5");
User userNull= null;
//orElse的工作方式非常直接,如果有值則返回該值,否則返回傳遞給它的參數(shù)值:
User user1 = Optional.ofNullable(userNull).orElse(user);
System.out.println(user1);
//控制臺(tái)輸出:User(name=王也, age=5)- orElseGet(Supplier other):如果optional不為空,則返回optional中的對(duì)象;如果為null,則使用Supplier函數(shù)生成默認(rèn)值other
User user1 = Optional.ofNullable(userNull).orElseGet(()->user ); //結(jié)果同上
- orElseThrow(Supplier exception):如果optional不為空,則返回optional中的對(duì)象;如果為null,則拋出Supplier函數(shù)生成的異常
//這個(gè)方法讓我們有更豐富的語義,可以決定拋出什么樣的異常,而不總是拋出 NullPointerException。
User result = Optional.ofNullable(userNull)
.orElseThrow( () -> new IllegalArgumentException());orElse() 和 orElseGet() 的不同之處
乍一看,這兩種方法似乎起著同樣的作用。然而事實(shí)并非如此。我們創(chuàng)建一些示例來突出二者行為上的異同。
(1)當(dāng)對(duì)象為空時(shí):
public class OptionalDemo {
public static void main(String[] args) {
User userNull = null;
System.out.println("使用orElse():");
User result = Optional.ofNullable(userNull).orElse(createNewUser());
System.out.println("使用orElseGet():");
User result2 = Optional.ofNullable(userNull).orElseGet(() -> createNewUser());
}
private static User createNewUser() {
System.out.println("Creating New User");
return new User("新的user對(duì)象", "1234");
}
}上面的代碼中,兩種方法都調(diào)用了 createNewUser() 方法,這個(gè)方法會(huì)記錄一個(gè)消息并返回 User 對(duì)象。
控制臺(tái)輸出:
使用orElse():
Creating New User
使用orElseGet():
Creating New User
由此可見,當(dāng)對(duì)象為空而返回默認(rèn)對(duì)象時(shí),行為并無差異。
(2)當(dāng)對(duì)象不為空時(shí):
public class OptionalDemo {
public static void main(String[] args) {
User user = new User("王也", "5");
System.out.println("使用orElse():");
User result = Optional.ofNullable(user).orElse(createNewUser());
System.out.println("使用orElseGet():");
User result2 = Optional.ofNullable(user).orElseGet(() -> createNewUser());
}
private static User createNewUser() {
System.out.println("Creating New User");
return new User("新的user對(duì)象", "1234");
}
}控制臺(tái)輸出:
使用orElse():
Creating New User
使用orElseGet():
這個(gè)示例中,兩個(gè) Optional 對(duì)象都包含非空值,兩個(gè)方法都會(huì)返回對(duì)應(yīng)的非空值。不過,orElse() 方法仍然創(chuàng)建了 User 對(duì)象。與之相反,orElseGet() 方法不創(chuàng)建 User 對(duì)象。
在執(zhí)行較密集的調(diào)用時(shí),比如調(diào)用 Web 服務(wù)或數(shù)據(jù)查詢,這個(gè)差異會(huì)對(duì)性能產(chǎn)生重大影響。
4. 過濾:
filter(Predicate p):filter() 接受一個(gè) Predicate 參數(shù),返回測(cè)試結(jié)果為 true 的值。如果測(cè)試結(jié)果為 false,會(huì)返回一個(gè)空的 Optional。
5. 映射:
- map(Function<T, U> mapper):如果optional不為空,則將optional中的對(duì)象 t 映射成另外一個(gè)對(duì)象 u,并將 u 存放到一個(gè)新的optional容器中。
- flatMap(Function<T,Optional > mapper):跟上面一樣,在optional不為空的情況下,將對(duì)象t映射成另外一個(gè)optional
map() 對(duì)值應(yīng)用(調(diào)用)作為參數(shù)的函數(shù),然后將返回的值包裝在 Optional 中。這就使對(duì)返回值進(jìn)行鏈試調(diào)用的操作成為可能 —— 這里的下一環(huán)就是 orElse()。
flatMap() 也需要函數(shù)作為參數(shù),并對(duì)值調(diào)用這個(gè)函數(shù),然后直接返回結(jié)果。
過濾和映射的示例
public class OptionalDemo {
public static void main(String[] args) {
List<Student> studentList = initData();
for (Student student : studentList) {
Optional<Student> studentOptional = Optional.of(student);
Integer score = studentOptional.filter(s -> s.getAge() >= 18).map(Student::getScore).orElse(0);
if (score > 80) {
System.out.println("入選:" + student.getName());
}
}
}
private static List<Student> initData(){
Student s1 = new Student("張三", 19, 80);
Student s2 = new Student("李四", 19, 50);
Student s3 = new Student("王五", 23, null);
Student s4 = new Student("趙六", 16, 90);
Student s5 = new Student("錢七", 18, 99);
Student s6 = new Student("孫八", 20, 40);
Student s7 = new Student("吳九", 21, 88);
return Arrays.asList(s1, s2, s3, s4, s5, s6, s7);
}
}使用stream流的寫法:
public static void main(String[] args) {
List<Student> studentList = initData();
List<String> studentName = studentList.stream().filter(student -> student.getAge() >= 18)
.filter(student -> student.getScore() != null && student.getScore() > 80)
.map(student -> student.getName()).collect(Collectors.toList());
System.out.println(studentName);
}控制臺(tái)輸出:
入選:錢七
入選:吳九
到此這篇關(guān)于淺談Java8的特性之Optional類的文章就介紹到這了,更多相關(guān)Java的Optional類內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot3和4的版本新特性及升級(jí)要點(diǎn)詳解
Spring Boot 4.0作為生態(tài)內(nèi)的重大更新,基于Spring Framework 6.1+ 構(gòu)建,帶來了一系列顛覆性優(yōu)化,這篇文章主要介紹了SpringBoot3和4的版本新特性及升級(jí)要點(diǎn)的相關(guān)資料,需要的朋友可以參考下2026-03-03
使用Java實(shí)現(xiàn)視頻與音頻轉(zhuǎn)碼
這篇文章主要為大家詳細(xì)介紹了如何使用Java實(shí)現(xiàn)視頻與音頻轉(zhuǎn)碼,即把其他視頻格式轉(zhuǎn)換成HTML5能播放的視頻格式和把其他音頻格式轉(zhuǎn)換為mp3,感興趣的小伙伴可以了解下2025-07-07
關(guān)于在使用Lombok時(shí)maven?install找不到符號(hào)問題的解決辦法
Maven環(huán)境下開發(fā)項(xiàng)目時(shí),尤其是涉及Lombok或其他依賴時(shí),IDE會(huì)在構(gòu)建和編譯過程中進(jìn)行注解處理,這篇文章主要介紹了關(guān)于在使用Lombok時(shí)maven?install找不到符號(hào)問題的解決辦法,需要的朋友可以參考下2025-10-10
SpringCloud?Hystrix?斷路器的實(shí)現(xiàn)
本文主要介紹了SpringCloud?Hystrix?斷路器的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2025-03-03
Java面向?qū)ο缶幊讨衒inal關(guān)鍵字的使用方法詳解
這篇文章主要介紹了Java面向?qū)ο缶幊讨衒inal關(guān)鍵字的使用方法詳解,包括對(duì)內(nèi)部匿名類無法訪問外面的非 final 的變量問題的解讀,需要的朋友可以參考下2016-06-06
關(guān)于application.yml數(shù)據(jù)庫配置方式
這篇文章主要介紹了關(guān)于application.yml數(shù)據(jù)庫配置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08

