日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java8使用 Optional 处理 null

發布時間:2023/12/3 java 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java8使用 Optional 处理 null 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載自??Java8(5):使用 Optional 處理 null

寫過 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?兩個方法,我們現在能寫出下面的代碼:

Optional<User> user = 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,否則什么也不做。
所以對于上面的例子,我們可以修改為:

Optional<User> user = 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) {Optional<User> user = userService.getUserById(id);return user.orElseThrow(() -> new EntityNotFoundException("id 為 " + id + " 的用戶不存在")); }@ExceptionHandler(EntityNotFoundException.class) public ResponseEntity<String> handleException(EntityNotFoundException ex) {return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND); }

5.map

?

如果當前?Optional?為?Optional.empty,則依舊返回?Optional.empty;否則返回一個新的?Optional,該?Optional包含的是:函數?mapper?在以?value?作為輸入時的輸出值。

Optional<String> username = Optional.ofNullable(getUserById(id)).map(user -> user.getUsername());System.out.println("Username is: " + username.orElse("Unknown"));

而且我們可以多次使用?map?操作:

Optional<String> username = Optional.ofNullable(getUserById(id)).map(user -> user.getUsername()).map(name -> name.toLowerCase()).map(name -> name.replace('_', ' '));System.out.println("Username is: " + username.orElse("Unknown"));

6.flatMap

?

flatMap?方法與?map?方法的區別在于,map?方法參數中的函數?mapper?輸出的是值,然后?map?方法會使用?Optional.ofNullable?將其包裝為?Optional;而?flatMap?要求參數中的函數?mapper?輸出的就是?Optional。

Optional<String> username = Optional.ofNullable(getUserById(id)).flatMap(user -> Optional.of(user.getUsername())).flatMap(name -> Optional.of(name.toLowerCase()));System.out.println("Username is: " + username.orElse("Unknown"));

7.filter

?

filter?方法接受一個?Predicate?來對?Optional?中包含的值進行過濾,如果包含的值滿足條件,那么還是返回這個?Optional;否則返回?Optional.empty。

Optional<String> username = Optional.ofNullable(getUserById(id)).filter(user -> user.getId() < 10).map(user -> user.getUsername());System.out.println("Username is: " + username.orElse("Unknown"));

有了?Optional,我們便可以方便且優雅的在自己的代碼中處理?null?值,而不再需要一昧通過容易忘記和麻煩的?if (object != null)?來判斷值不為?null。如果你的程序還在使用 Java8 之前的 JDK,可以考慮引入 Google 的 Guava 庫 —— 事實上,早在 Java6 的年代,Guava 就提供了?Optional?的實現。


號外:Java9 對?Optional?的增強
即將在今年 7 月到來的 JDK9 中,在?Optional?類中添加了三個新的方法:

  • public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)
  • 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<T> stream()
  • stream?方法的作用就是將?Optional?轉為一個?Stream,如果該?Optional?中包含值,那么就返回包含這個值的?Stream;否則返回一個空的?Stream(Stream.empty())。
    舉個例子,在 Java8,我們會寫下面的代碼:

    // 此處 getUserById 返回的是 Optional<User> public List<User> getUsers(Collection<Integer> userIds) {return userIds.stream().map(this::getUserById) // 獲得 Stream<Optional<User>>.filter(Optional::isPresent)// 去掉不包含值的 Optional.map(Optional::get).collect(Collectors.toList()); }

    而有了?Optional.stream(),我們就可以將其簡化為:

    public List<User> getUsers(Collection<Integer> userIds) {return userIds.stream().map(this::getUserById) // 獲得 Stream<Optional<User>>.flatMap(Optional::stream) // Stream 的 flatMap 方法將多個流合成一個流.collect(Collectors.toList()); }

    總結

    以上是生活随笔為你收集整理的Java8使用 Optional 处理 null的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。