淺談Java8的特性之Optional類
一、Optional類 簡介
Optional類是 Java 8 引入的一個很有趣的特性。它主要解決的問題是臭名昭著的空指針異常(NullPointerException)
- Optional 類是一個可以為null的容器對象。如果值存在則isPresent()方法會返回true,調(diào)用get()方法會返回該對象。
- Optional 是個容器:它可以保存類型T的值,或者僅僅保存null。Optional提供很多有用的方法,這樣我們就不用顯式進(jìn)行空值檢測。
- Optional 類的引入很好的解決空指針異常。
Optional 是一個對象容器,具有以下兩個特點(diǎn):
- 提示用戶要注意該對象有可能為null
- 簡化if else代碼
舉一個簡單的例子,在 Java 8 之前,任何訪問對象方法或?qū)傩缘恼{(diào)用都可能導(dǎo)致 NullPointerException:
用戶 -> 家庭住址 -> 城市 ->郵編 String postCode = user.getAddress().getCity().getPostCode();
在這個示例中,為了避免異常,就得在訪問每一個值之前對其進(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) { //對postCode進(jìn)行操作 test(postCode); } } } }
這很容易就變得冗長,難以維護(hù)。 為了簡化這個過程,我們就可以用 Optional 類。
二、Optional類的使用
1. 創(chuàng)建:
Optional類的實例創(chuàng)建有三種方式:
- Optional.empty() :創(chuàng)建一個空的 Optional 實例。
- Optional.of(T t) :創(chuàng)建一個 Optional 實例,當(dāng) t為null時拋出異常(NullPointerException)。
- Optional.ofNullable(T t) :創(chuàng)建一個 Optional 實例,但當(dāng) t為null時不會拋出異常,而是返回一個空的實例。
2. 獲?。?/h3>
- get():獲取optional實例中的對象,當(dāng)optional 容器為空時報錯。
3. 判斷:
- isPresent():判斷optional是否為空,如果空則返回false,否則返回true
- ifPresent(Consumer c):如果optional不為空,則將optional中的對象傳給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中的對象;如果為null,則返回 other 這個默認(rèn)值
User user = new User("王也", "5"); User userNull= null; //orElse的工作方式非常直接,如果有值則返回該值,否則返回傳遞給它的參數(shù)值: User user1 = Optional.ofNullable(userNull).orElse(user); System.out.println(user1); //控制臺輸出:User(name=王也, age=5)
- orElseGet(Supplier other):如果optional不為空,則返回optional中的對象;如果為null,則使用Supplier函數(shù)生成默認(rèn)值other
User user1 = Optional.ofNullable(userNull).orElseGet(()->user ); //結(jié)果同上
- orElseThrow(Supplier exception):如果optional不為空,則返回optional中的對象;如果為null,則拋出Supplier函數(shù)生成的異常
//這個方法讓我們有更豐富的語義,可以決定拋出什么樣的異常,而不總是拋出 NullPointerException。 User result = Optional.ofNullable(userNull) .orElseThrow( () -> new IllegalArgumentException());
orElse() 和 orElseGet() 的不同之處
乍一看,這兩種方法似乎起著同樣的作用。然而事實并非如此。我們創(chuàng)建一些示例來突出二者行為上的異同。
(1)當(dāng)對象為空時:
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對象", "1234"); } }
上面的代碼中,兩種方法都調(diào)用了 createNewUser() 方法,這個方法會記錄一個消息并返回 User 對象。
控制臺輸出:
使用orElse():
Creating New User
使用orElseGet():
Creating New User
由此可見,當(dāng)對象為空而返回默認(rèn)對象時,行為并無差異。
(2)當(dāng)對象不為空時:
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對象", "1234"); } }
控制臺輸出:
使用orElse():
Creating New User
使用orElseGet():
這個示例中,兩個 Optional 對象都包含非空值,兩個方法都會返回對應(yīng)的非空值。不過,orElse() 方法仍然創(chuàng)建了 User 對象。與之相反,orElseGet() 方法不創(chuàng)建 User 對象。
在執(zhí)行較密集的調(diào)用時,比如調(diào)用 Web 服務(wù)或數(shù)據(jù)查詢,這個差異會對性能產(chǎn)生重大影響。
4. 過濾:
filter(Predicate p):filter() 接受一個 Predicate 參數(shù),返回測試結(jié)果為 true 的值。如果測試結(jié)果為 false,會返回一個空的 Optional。
5. 映射:
- map(Function<T, U> mapper):如果optional不為空,則將optional中的對象 t 映射成另外一個對象 u,并將 u 存放到一個新的optional容器中。
- flatMap(Function<T,Optional > mapper):跟上面一樣,在optional不為空的情況下,將對象t映射成另外一個optional
map() 對值應(yīng)用(調(diào)用)作為參數(shù)的函數(shù),然后將返回的值包裝在 Optional 中。這就使對返回值進(jìn)行鏈試調(diào)用的操作成為可能 —— 這里的下一環(huán)就是 orElse()。
flatMap() 也需要函數(shù)作為參數(shù),并對值調(diào)用這個函數(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); }
控制臺輸出:
入選:錢七
入選:吳九
到此這篇關(guān)于淺談Java8的特性之Optional類的文章就介紹到這了,更多相關(guān)Java的Optional類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
對java for 循環(huán)執(zhí)行順序的詳解
今天小編就為大家分享一篇對java for 循環(huán)執(zhí)行順序的詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-06-06一文詳解Elasticsearch和MySQL之間的數(shù)據(jù)同步問題
Elasticsearch中的數(shù)據(jù)是來自于Mysql數(shù)據(jù)庫的,因此當(dāng)數(shù)據(jù)庫中的數(shù)據(jù)進(jìn)行增刪改后,Elasticsearch中的數(shù)據(jù),索引也必須跟著做出改變。本文主要來和大家探討一下Elasticsearch和MySQL之間的數(shù)據(jù)同步問題,感興趣的可以了解一下2023-04-04java實現(xiàn)文件復(fù)制、剪切文件和刪除示例
這篇文章主要介紹了java實現(xiàn)文件復(fù)制、剪切文件和刪除示例,需要的朋友可以參考下2014-04-04