摘要:與方法的區別在于,方法傳入的參數為一個接口的實現當中有值的時候,返回值當中沒有值的時候,返回從該獲得的值。為的用戶沒有找到舉一個的用途在的控制器中,我們可以配置統一處理各種異常。
寫過 Java 程序的同學,一般都遇到過 NullPointerException :) —— 為了不拋出這個異常,我們便會寫如下的代碼:
User user = getUserById(id); if (user != null) { String username = user.getUsername(); System.out.println("Username is: " + username); // 使用 username }
但是很多時候,我們可能會忘記寫 if (user != null) —— 如果在開發階段就發現那還好,但是如果在開發階段沒有測試到問題,等到上線卻出了 NullPointerException ... 畫面太美,我不敢繼續想下去。
為了解決這種尷尬的處境,JDK 終于在 Java8 的時候加入了 Optional 類,查看 Optional 的 javadoc 介紹:
A container object which may or may not contain a non-null value. If a value is present, isPresent() will return true and get() will return the value.
這是一個可以包含或者不包含非 null 值的容器。如果值存在則 isPresent()方法會返回 true,調用 get() 方法會返回該對象。
JDK 提供三個靜態方法來構造一個 Optional:
1.Optional.of(T value),該方法通過一個非 null 的 value 來構造一個 Optional,返回的 Optional 包含了 value 這個值。對于該方法,傳入的參數一定不能為 null,否則便會拋出 NullPointerException。
2.Optional.ofNullable(T value),該方法和 of 方法的區別在于,傳入的參數可以為 null —— 但是前面 javadoc 不是說 Optional 只能包含非 null 值嗎?我們可以看看 ofNullable 方法的源碼:
原來該方法會判斷傳入的參數是否為 null,如果為 null 的話,返回的就是 Optional.empty()。
3.Optional.empty(),該方法用來構造一個空的 Optional,即該 Optional 中不包含值 —— 其實底層實現還是 如果 Optional 中的 value 為 null 則該 Optional 為不包含值的狀態,然后在 API 層面將 Optional 表現的不能包含 null 值,使得 Optional 只存在 包含值 和 不包含值 兩種狀態。
前面 javadoc 也有提到,Optional 的 isPresent() 方法用來判斷是否包含值,get() 用來獲取 Optional 包含的值 —— 值得注意的是,如果值不存在,即在一個Optional.empty 上調用 get() 方法的話,將會拋出 NoSuchElementException 異常。
我們假設 getUserById 已經是個客觀存在的不能改變的方法,那么利用 isPresent 和 get 兩個方法,我們現在能寫出下面的代碼:
Optionaluser = Optional.ofNullable(getUserById(id)); if (user.isPresent()) { String username = user.get().getUsername(); System.out.println("Username is: " + username); // 使用 username }
好像看著代碼是優美了點 —— 但是事實上這與之前判斷 null 值的代碼沒有本質的區別,反而用 Optional 去封裝 value,增加了代碼量。所以我們來看看 Optional 還提供了哪些方法,讓我們更好的(以正確的姿勢)使用 Optional。
1.ifPresent
如果 Optional 中有值,則對該值調用 consumer.accept,否則什么也不做。
所以對于上面的例子,我們可以修改為:
Optionaluser = Optional.ofNullable(getUserById(id)); user.ifPresent(u -> System.out.println("Username is: " + u.getUsername()));
2.orElse
如果 Optional 中有值則將其返回,否則返回 orElse 方法傳入的參數。
User user = Optional .ofNullable(getUserById(id)) .orElse(new User(0, "Unknown")); System.out.println("Username is: " + user.getUsername());
3.orElseGet
orElseGet 與 orElse 方法的區別在于,orElseGet 方法傳入的參數為一個 Supplier 接口的實現 —— 當 Optional 中有值的時候,返回值;當 Optional 中沒有值的時候,返回從該 Supplier 獲得的值。
User user = Optional .ofNullable(getUserById(id)) .orElseGet(() -> new User(0, "Unknown")); System.out.println("Username is: " + user.getUsername());
4.orElseThrow
orElseThrow 與 orElse 方法的區別在于,orElseThrow 方法當 Optional 中有值的時候,返回值;沒有值的時候會拋出異常,拋出的異常由傳入的 exceptionSupplier 提供。
User user = Optional .ofNullable(getUserById(id)) .orElseThrow(() -> new EntityNotFoundException("id 為 " + id + " 的用戶沒有找到"));
舉一個 orElseThrow 的用途:在 SpringMVC 的控制器中,我們可以配置統一處理各種異常。查詢某個實體時,如果數據庫中有對應的記錄便返回該記錄,否則就可以拋出 EntityNotFoundException ,處理 EntityNotFoundException 的方法中我們就給客戶端返回Http 狀態碼 404 和異常對應的信息 —— orElseThrow 完美的適用于這種場景。
@RequestMapping("/{id}") public User getUser(@PathVariable Integer id) { Optionaluser = userService.getUserById(id); return user.orElseThrow(() -> new EntityNotFoundException("id 為 " + id + " 的用戶不存在")); } @ExceptionHandler(EntityNotFoundException.class) public ResponseEntity handleException(EntityNotFoundException ex) { return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND); }
5.map
如果當前 Optional 為 Optional.empty,則依舊返回 Optional.empty;否則返回一個新的 Optional,該 Optional 包含的是:函數 mapper 在以 value 作為輸入時的輸出值。
String username = Optional.ofNullable(getUserById(id)) .map(user -> user.getUsername()) .orElse("Unknown") .ifPresent(name -> System.out.println("Username is: " + name));
而且我們可以多次使用 map 操作:
Optionalusername = Optional.ofNullable(getUserById(id)) .map(user -> user.getUsername()) .map(name -> name.toLowerCase()) .map(name -> name.replace("_", " ")) .orElse("Unknown") .ifPresent(name -> System.out.println("Username is: " + name));
6.flatMap
flatMap 方法與 map 方法的區別在于,map 方法參數中的函數 mapper 輸出的是值,然后 map 方法會使用 Optional.ofNullable 將其包裝為 Optional;而 flatMap 要求參數中的函數 mapper 輸出的就是 Optional。
Optionalusername = Optional.ofNullable(getUserById(id)) .flatMap(user -> Optional.of(user.getUsername())) .flatMap(name -> Optional.of(name.toLowerCase())) .orElse("Unknown") .ifPresent(name -> System.out.println("Username is: " + name));
7.filter
filter 方法接受一個 Predicate 來對 Optional 中包含的值進行過濾,如果包含的值滿足條件,那么還是返回這個 Optional;否則返回 Optional.empty。
Optionalusername = Optional.ofNullable(getUserById(id)) .filter(user -> user.getId() < 10) .map(user -> user.getUsername()); .orElse("Unknown") .ifPresent(name -> System.out.println("Username is: " + name));
有了 Optional,我們便可以方便且優雅的在自己的代碼中處理 null 值,而不再需要一昧通過容易忘記和麻煩的 if (object != null) 來判斷值不為 null。如果你的程序還在使用 Java8 之前的 JDK,可以考慮引入 Google 的 Guava 庫 —— 事實上,早在 Java6 的年代,Guava 就提供了 Optional 的實現。
號外:Java9 對 Optional 的增強
即將在今年 7 月到來的 JDK9 中,在 Optional 類中添加了三個新的方法:
public Optional
or 方法的作用是,如果一個 Optional 包含值,則返回自己;否則返回由參數 supplier 獲得的 Optional
public void ifPresentOrElse(Consumer super T> action, Runnable emptyAction)
ifPresentOrElse 方法的用途是,如果一個 Optional 包含值,則對其包含的值調用函數 action,即 action.accept(value),這與 ifPresent 一致;與 ifPresent 方法的區別在于,ifPresentOrElse 還有第二個參數 emptyAction —— 如果 Optional 不包含值,那么 ifPresentOrElse 便會調用 emptyAction,即 emptyAction.run()
public Stream
stream 方法的作用就是將 Optional 轉為一個 Stream,如果該 Optional 中包含值,那么就返回包含這個值的 Stream;否則返回一個空的 Stream(Stream.empty())。
舉個例子,在 Java8,我們會寫下面的代碼:
// 此處 getUserById 返回的是 Optionalpublic List getUsers(Collection userIds) { return userIds.stream() .map(this::getUserById) // 獲得 Stream > .filter(Optional::isPresent) // 去掉不包含值的 Optional,否則如果存在為空的 Optional 下面的 get 會拋出異常 .map(Optional::get) // 變為 Stream .collect(Collectors.toList()); }
而有了 Optional.stream(),我們就可以將其簡化為:
public ListgetUsers(Collection userIds) { return userIds.stream() .map(this::getUserById) // 獲得 Stream > .flatMap(Optional::stream) // Stream 的 flatMap 方法將多個流合成一個流,如果 Optional 為空則對應是空的 Stream,合并時會跳過 .collect(Collectors.toList()); }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66812.html
摘要:大家好啊,上次小樂給大家介紹了最最重要的一個特性流,點擊可以回顧哦。并且可以避免空指針異常。這種操作對于參數判斷提供很大便利,例如參數滿足指定條件的后續操作查詢操作字符串拼接,常見的處理多請求頁面轉發處理等操作。 大家好啊,上次小樂給大家介紹了Java8最最重要的一個特性——Stream流,點擊可以回顧哦。 Optional類(java.util.Optional)是一個容器類,代表一...
摘要:上一篇小樂帶大家了解了新特性之,接下來將會繼續述說新特性之類是一個容器類,代表一個值存在或不存在,原來用表示一個值不存在,現在可以更好的表達這個概念。并且可以避免空指針異常。如果有值則將其返回,否則拋出。隱士地其中進行了判斷。 上一篇小樂帶大家了解了Java8新特性之Stream,接下來將會繼續述說Java新特性之Optional showImg(https://segmentfaul...
摘要:本文已收錄修煉內功躍遷之路的為解決空的問題帶來了很多新思路,查看源碼,實現非常簡單,邏輯也并不復雜。 本文已收錄【修煉內功】躍遷之路 showImg(https://segmentfault.com/img/bVbrCvp?w=852&h=480); Java8的Optional為解決空的問題帶來了很多新思路,查看Optional源碼,實現非常簡單,邏輯也并不復雜。Stuart Ma...
摘要:函數副作用會給程序設計帶來不必要的麻煩,引入潛在的,并降低程序的可讀性。所以只能采用這種曲線救國的方式。則是把這種曲線救國拿到了臺面上,并昭告天下,同時還對提供了一些語法支持。是自由變量,提供執行上下文,觸發閉包執行。 背景 自從2013年放棄了Java就再也沒有碰過。期間Java還發布了重大更新:引入lambda,但是那會兒我已經玩了一段時間Scala,對Java已經瞧不上眼。相比S...
摘要:上一篇我們詳細介紹了函數式接口中主要的一些方法使用,本篇介紹的雖然并不是一個函數式接口,但是也是一個極其重要的類。并不是我們之前介紹的一系列函數式接口,它是一個,主要作用就是解決中的。 上一篇我們詳細介紹了Predicate函數式接口中主要的一些方法使用,本篇介紹的Optional雖然并不是一個函數式接口,但是也是一個極其重要的類。 Optional并不是我們之前介紹的一系列函數式接口...
閱讀 1619·2021-11-11 10:59
閱讀 2624·2021-09-04 16:40
閱讀 3650·2021-09-04 16:40
閱讀 2979·2021-07-30 15:30
閱讀 1615·2021-07-26 22:03
閱讀 3164·2019-08-30 13:20
閱讀 2225·2019-08-29 18:31
閱讀 439·2019-08-29 12:21