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