optional 關鍵字用于優雅地處理可能為空的值,減少空指針異常。1. 創建 optional 對象有三種方式:of() 適用于非空值,ofNULLable() 可處理空值,empty() 創建空對象;2. 檢查值是否存在推薦使用 orelse 系列方法替代 ispresent();3. 獲取值常用 orelse() 提供默認值,orelseget() 延遲計算默認值,orelsethrow() 拋出指定異常;4. 鏈式操作通過 map、flatmap 和 Filter 方法簡化嵌套判斷。同時應避免過度使用 optional,如不作為類字段、不作方法參數、謹慎用于集合處理。optional 常應用于數據庫查詢、外部 api 返回、配置讀取等場景,盡管帶來輕微性能開銷,但提升了代碼健壯性與可維護性。
Optional 關鍵字主要用于解決 Java 中長期存在的空指針異常(NullPointerException)問題,它提供了一種更優雅的方式來處理可能為空的值,避免了顯式的 null 檢查。本質上,Optional 是一個容器對象,它可能包含一個非空值,也可能為空。
Optional 的 4 個實用技巧
-
創建 Optional 對象
- Optional.of(value): 如果 value 為 null,則拋出 NullPointerException。適用于你確定 value 絕對不會為空的情況。
- Optional.ofNullable(value): 如果 value 為 null,則創建一個空的 Optional 對象。這是最常用的創建方式,因為它能處理 value 為空的情況。
- Optional.empty(): 創建一個空的 Optional 對象。
選擇哪種方式取決于你對值的空安全性的保證程度。如果明確知道值不會為空,Optional.of() 是一個不錯的選擇,否則,Optional.ofNullable() 更安全。
立即學習“Java免費學習筆記(深入)”;
-
檢查 Optional 對象是否包含值
- isPresent(): 如果 Optional 對象包含一個非空值,則返回 true,否則返回 false。
雖然可以使用 isPresent() 來檢查值是否存在,但更推薦使用 orElse(), orElseGet(), orElseThrow() 等方法來處理值不存在的情況,而不是簡單地檢查然后手動取值,這樣可以更簡潔地表達你的意圖。
-
獲取 Optional 對象中的值
- get(): 如果 Optional 對象包含一個值,則返回該值;否則拋出 NoSuchElementException。不推薦直接使用 get() 方法,因為它可能會拋出異常。
- orElse(defaultValue): 如果 Optional 對象包含一個值,則返回該值;否則返回 defaultValue。
- orElseGet(Supplier extends T> supplier): 如果 Optional 對象包含一個值,則返回該值;否則返回由 supplier 函數生成的值。 orElseGet() 適合于 defaultValue 的計算成本較高的情況,因為它只有在 Optional 為空時才會執行 supplier 函數。
- orElseThrow(Supplier extends X> exceptionSupplier): 如果 Optional 對象包含一個值,則返回該值;否則拋出由 exceptionSupplier 函數生成的異常。
例如,你想從一個配置中獲取超時時間,如果配置中沒有設置,則使用默認值:
String timeout = Optional.ofNullable(System.getProperty("timeout")) .orElse("1000"); // 默認 1000 毫秒
-
使用 Optional 對象進行鏈式操作
- map(function super T, ? extends U> mapper): 如果 Optional 對象包含一個值,則將該值傳遞給 mapper 函數,并將 mapper 函數的返回值封裝成一個新的 Optional 對象返回;否則返回一個空的 Optional 對象。
- flatMap(Function super T, Optional> mapper): 與 map() 方法類似,但 mapper 函數的返回值必須是一個 Optional 對象。flatMap() 方法用于處理嵌套的 Optional 對象。
- filter(Predicate super T> predicate): 如果 Optional 對象包含一個值,并且該值滿足 predicate 條件,則返回包含該值的 Optional 對象;否則返回一個空的 Optional 對象。
鏈式操作可以讓你以一種流暢的方式處理可能為空的值,避免了大量的嵌套 if 語句。 比如,你需要從一個 User 對象中獲取其地址的郵政編碼,如果 User 對象為空,或者地址為空,則返回 “N/A”:
String zipCode = Optional.ofNullable(user) .map(User::getAddress) .map(Address::getZipCode) .orElse("N/A");
如何避免過度使用 Optional?
過度使用 Optional 會導致代碼可讀性下降,增加不必要的復雜性。以下是一些建議:
- 不要將 Optional 作為類的字段: Optional 主要用于表示方法的返回值,而不是類的狀態。將 Optional 作為類的字段會增加類的復雜性,并可能導致序列化問題。
- 不要將 Optional 作為方法參數: 使用方法重載或提供默認值是更好的選擇。
- 謹慎使用 Optional 處理集合: 處理集合時,使用流式操作(Stream API)通常更簡潔。例如,從一個列表中找到第一個滿足條件的元素,可以使用 list.stream().filter(…).findFirst(),它返回一個 Optional 對象。
- 不要為了使用 Optional 而使用 Optional: 如果一個值永遠不應該為空,則不要使用 Optional。使用斷言(assert)或拋出異常可能更合適。
Optional 在實際項目中的應用場景
- 處理數據庫查詢結果: 當從數據庫查詢數據時,如果查詢結果可能為空,可以使用 Optional 來封裝查詢結果。
- 處理外部 API 的返回值: 當調用外部 API 時,API 的返回值可能為空,可以使用 Optional 來處理返回值。
- 配置文件的讀取: 從配置文件中讀取配置項時,配置項可能不存在,可以使用 Optional 來處理配置項。
Optional 和 null 的性能差異
Optional 本身會帶來一定的性能開銷,因為它需要創建一個新的對象。但在大多數情況下,這種開銷可以忽略不計。相比于空指針異常帶來的風險和調試成本,使用 Optional 帶來的好處通常大于其性能開銷。
總而言之,Optional 是一個強大的工具,可以幫助你編寫更健壯、更易于維護的代碼。但是,你需要謹慎使用 Optional,避免過度使用,并根據實際情況選擇最合適的處理方式。