成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Nacos中已經有Optional使用案例了,是時候慎重對待這一語法了

開發 后端
Java 8提供了很多新特性,但很多朋友對此并不重視,依舊采用老的寫法。最近個人在大量閱讀開源框架的源碼,發現Java 8的很多API已經被頻繁的使用了。

[[398310]]

本文轉載自微信公眾號「程序新視界」,作者二師兄。轉載本文請聯系程序新視界公眾號。

前言

Java 8提供了很多新特性,但很多朋友對此并不重視,依舊采用老的寫法。最近個人在大量閱讀開源框架的源碼,發現Java 8的很多API已經被頻繁的使用了。

以Nacos框架為例,已經有很典型的Optional使用案例了,而且場景把握的非常好。如果此時你還沒意識到要學習了解一下,以后看源代碼可能都有些費勁了。

今天這篇文章我們就基于Nacos中對Optional的使用作為案例,來深入講解一下Optional的使用。老規矩,源碼、案例、實戰,一樣不少。

Nacos中的Optional使用

在Nacos中有這樣一個接口ConsistencyService,用來定義一致性服務的,其中的一個方法返回的類型便是Optional:

  1. /** 
  2.  * Get the error message of the consistency protocol. 
  3.  * 
  4.  * @return the consistency protocol error message. 
  5.  */ 
  6. Optional<String> getErrorMsg(); 

如果你對Optional不了解,看到這里可能就會有點蒙。那我們來看看Nacos是怎么使用Optional的。在上述接口的一個實現類PersistentServiceProcessor中是如此實現的:

  1. @Override 
  2. public Optional<String> getErrorMsg() { 
  3.     String errorMsg; 
  4.     if (hasLeader && hasError) { 
  5.         errorMsg = "The raft peer is in error: " + jRaftErrorMsg; 
  6.     } else if (hasLeader && !hasError) { 
  7.         errorMsg = null
  8.     } else if (!hasLeader && hasError) { 
  9.         errorMsg = "Could not find leader! And the raft peer is in error: " + jRaftErrorMsg; 
  10.     } else { 
  11.         errorMsg = "Could not find leader!"
  12.     } 
  13.     return Optional.ofNullable(errorMsg); 

也就是根據hasLeader和hasError兩個變量來確定返回的errorMsg信息是什么。最后將errorMsg封裝到Optional中進行返回。

下面再看看方法getErrorMsg是如何被調用的:

  1. String errorMsg; 
  2. if (ephemeralConsistencyService.getErrorMsg().isPresent() 
  3.         && persistentConsistencyService.getErrorMsg().isPresent()) { 
  4.     errorMsg = "'" + ephemeralConsistencyService.getErrorMsg().get() + "' in Distro protocol and '" 
  5.             + persistentConsistencyService.getErrorMsg().get() + "' in jRaft protocol"

可以看到在使用時只用先調用返回的Optional的isPresent方法判斷是否存在,再調用其get方法獲取即可。此時你可以回想一下如果不用Optional該如何實現。

到此,你可能有所疑惑用法,沒關系,下面我們就開始逐步講解Option的使用、原理和源碼。

Optional的數據結構

面對新生事物我們都會有些許畏懼,當我們庖丁解牛似的將其拆分之后,了解其實現原理,就沒那么恐怖了。

查看Optional類的源碼,可以看到它有兩個成員變量:

  1. public final class Optional<T> { 
  2.     /** 
  3.      * Common instance for {@code empty()}. 
  4.      */ 
  5.     private static final Optional<?> EMPTY = new Optional<>(null); 
  6.  
  7.     /** 
  8.      * If non-null, the value; if null, indicates no value is present 
  9.      */ 
  10.     private final T value; 
  11.     // ... 

其中EMPTY變量表示的是如果創建一個空的Optional實例,很顯然,在加載時已經初始化了。而value是用來存儲我們業務中真正使用的對象,比如上面的errorMsg就是存儲在這里。

看到這里你是否意識到Optional其實就一個容器啊!對的,將Optional理解為容器就對了,然后這個容器呢,為我們封裝了存儲對象的非空判斷和獲取的API。

看到這里,是不是感覺Optional并沒那么神秘了?是不是也沒那么恐懼了?

而Java 8之所以引入Optional也是為了解決對象使用時為避免空指針異常的丑陋寫法問題。類似如下代碼:

  1. if( user != null){ 
  2.     Address address = user.getAddress(); 
  3.     if(address != null){ 
  4.         String province = address.getProvince(); 
  5.     } 

原來是為了封裝,原來是為了更優雅的代碼,這不正是我們有志向的程序員所追求的么。

如何將對象存入Optional容器中

這么我們就姑且稱Optional為Optional容器了,下面就看看如何將對象放入Optional當中。

看到上面的EMPTY初始化時調用了構造方法,傳入null值,我們是否也可以這樣來封裝對象?好像不行,來看一下Optional的構造方法:

  1. private Optional() { 
  2.     this.value = null
  3.  
  4. private Optional(T value) { 
  5.     this.value = Objects.requireNonNull(value); 

存在的兩個構造方法都是private的,看來只能通過Optional提供的其他方法來封裝對象了,通常有以下方式。

empty方法

empty方法源碼如下:

  1. // Returns an {@code Optional} with the specified present non-null value. 
  2. public static <T> Optional<T> of(T value) { 
  3.     return new Optional<>(value); 

簡單直接,直接強轉EMPTY對象。

of方法

of方法源碼如下:

  1. public static <T> T requireNonNull(T obj) { 
  2.     if (obj == null
  3.         throw new NullPointerException(); 
  4.     return obj; 

注釋上說是為非null的值創建一個Optional,而非null的是通過上面構造方法中的Objects.requireNonNull方法來檢查的:

  1. public static <T> T requireNonNull(T obj) { 
  2.     if (obj == null
  3.         throw new NullPointerException(); 
  4.     return obj; 

也就是說如果值為null,則直接拋空指針異常。

ofNullable方法

ofNullable方法源碼如下:

  1. public static <T> Optional<T> ofNullable(T value) { 
  2.     return value == null ? empty() : of(value); 

ofNullable為指定的值創建一個Optional,如果指定的值為null,則返回一個空的Optional。也就是說此方法支持對象的null與非null構造。

回顧一下:Optional構造方法私有,不能被外部調用;empty方法創建空的Optional、of方法創建非空的Optional、ofNullable將兩者結合。是不是so easy?

此時,有朋友可能會問,相對于ofNullable方法,of方法存在的意義是什么?在運行過程中,如果不想隱藏NullPointerException,就是說如果出現null則要立即報告,這時就用Of函數。另外就是已經明確知道value不會為null的時候也可以使用。

判斷對象是否存在

上面已經將對象放入Optional了,那么在獲取之前是否需要能判斷一下存放的對象是否為null呢?

isPresent方法

上述問題,答案是:可以的。對應的方法就是isPresent:

  1. public boolean isPresent() { 
  2.     return value != null

實現簡單直白,相當于將obj != null的判斷進行了封裝。該對象如果存在,方法返回true,否則返回false。

isPresent即判斷value值是否為空,而ifPresent就是在value值不為空時,做一些操作:

  1. public void ifPresent(Consumer<? super T> consumer) { 
  2.     if (value != null
  3.         consumer.accept(value); 

如果Optional實例有值則為其調用consumer,否則不做處理。可以直接將Lambda表達式傳遞給該方法,代碼更加簡潔、直觀。

  1. Optional<String> opt = Optional.of("程序新視界"); 
  2. opt.ifPresent(System.out::println); 

獲取值

當我們判斷Optional中有值時便可以進行獲取了,像Nacos中使用的那樣,調用get方法:

  1. public T get() { 
  2.     if (value == null) { 
  3.         throw new NoSuchElementException("No value present"); 
  4.     } 
  5.     return value; 

很顯然,如果value值為null,則該方法會拋出NoSuchElementException異常。這也是為什么我們在使用時要先調用isPresent方法來判斷一下value值是否存在了。此處的設計稍微與初衷相悖。

看一下使用示例:

  1. String name = null
  2. Optional<String> opt = Optional.ofNullable(name); 
  3. if(opt.isPresent()){ 
  4.     System.out.println(opt.get()); 

設置(或獲取)默認值

那么,針對上述value為null的情況是否有解決方案呢?我們可以配合設置(或獲取)默認值來解決。

orElse方法

orElse方法:如果有值則將其返回,否則返回指定的其它值。

  1. public T orElse(T other) { 
  2.     return value != null ? value : other; 

可以看到是get方法的加強版,get方法如果值為null直接拋異常,orElse則不,如果只為null,返回你傳入進來的參數值。

使用示例:

  1. Optional<Object> o1 = Optional.ofNullable(null); 
  2. // 輸出orElse指定值 
  3. System.out.println(o1.orElse("程序新視界")); 

orElseGet方法

orElseGet:orElseGet與orElse方法類似,區別在于得到的默認值。orElse方法將傳入的對象作為默認值,orElseGet方法可以接受Supplier接口的實現用來生成默認值:

  1. public T orElseGet(Supplier<? extends T> other) { 
  2.     return value != null ? value : other.get(); 

當value為null時orElse直接返回傳入值,orElseGet返回Supplier實現類中定義的值。

  1. String name = null
  2. String newName = Optional.ofNullable(name).orElseGet(()->"程序新視界"); 
  3. System.out.println(newName); // 輸出:程序新視界 

其實上面的示例可以直接優化為orElse,因為Supplier接口的實現依舊是直接返回輸入值。

orElseThrow方法

orElseThrow:如果有值則將其返回,否則拋出Supplier接口創建的異常。

  1. public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X { 
  2.     if (value != null) { 
  3.         return value; 
  4.     } else { 
  5.         throw exceptionSupplier.get(); 
  6.     } 

使用示例:

  1. Optional<Object> o = Optional.ofNullable(null); 
  2. try { 
  3.   o.orElseThrow(() -> new Exception("異常")); 
  4. } catch (Exception e) { 
  5.   System.out.println(e.getMessage()); 

學完上述內容,基本上已經掌握了Optional百分之八十的功能了。同時,還有兩個相對高級點的功能:過濾值和轉換值。

filter方法過濾值

Optional中的值我們可以通過上面講的到方法進行獲取,但在某些場景下,我們還需要判斷一下獲得的值是否符合條件。笨辦法時,獲取值之后,自己再進行檢查判斷。

當然,也可以通過Optional提供的filter來進行取出前的過濾:

  1. public Optional<T> filter(Predicate<? super T> predicate) { 
  2.     Objects.requireNonNull(predicate); 
  3.     if (!isPresent()) 
  4.         return this; 
  5.     else 
  6.         return predicate.test(value) ? this : empty(); 

filter方法的參數類型為Predicate類型,可以將Lambda表達式傳遞給該方法作為條件,如果表達式的結果為false,則返回一個EMPTY的Optional對象,否則返回經過過濾的Optional對象。

使用示例:

  1. Optional<String> opt = Optional.of("程序新視界"); 
  2. Optional<String> afterFilter = opt.filter(name -> name.length() > 4); 
  3. System.out.println(afterFilter.orElse("")); 

map方法轉換值

與filter方法類似,當我們將值從Optional中取出之后,還進行一步轉換,比如改為大寫或返回長度等操作。當然可以用笨辦法取出之后,進行處理。

這里,Optional為我們提供了map方法,可以在取出之前就進行操作:

  1. public<U> Optional<U> map(Function<? super T, ? extends U> mapper) { 
  2.     Objects.requireNonNull(mapper); 
  3.     if (!isPresent()) 
  4.         return empty(); 
  5.     else { 
  6.         return Optional.ofNullable(mapper.apply(value)); 
  7.     } 

map方法的參數類型為Function,會調用Function的apply方法對對Optional中的值進行處理。如果Optional中的值本身就為null,則返回空,否則返回處理過后的值。

示例:

  1. Optional<String> opt = Optional.of("程序新視界"); 
  2. Optional<Integer> intOpt = opt.map(String::length); 
  3. System.out.println(intOpt.orElse(0)); 

與map方法有這類似功能的方法為flatMap:

  1. public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) { 
  2.     Objects.requireNonNull(mapper); 
  3.     if (!isPresent()) 
  4.         return empty(); 
  5.     else { 
  6.         return Objects.requireNonNull(mapper.apply(value)); 
  7.     } 

可以看出,它與map方法的實現非常像,不同的是傳入的參數類型,map函數所接受的入參類型為Function,而flapMap的入參類型為Function>。

flapMap示例如下:

  1. Optional<String> opt = Optional.of("程序新視界"); 
  2. Optional<Integer> intOpt = opt.flatMap(name ->Optional.of(name.length())); 
  3. System.out.println(intOpt.orElse(0)); 

對照map的示例,可以看出在flatMap中對結果進行了一次Optional#of的操作。

小結

本文我們從Nacos中使用Optional的使用出發,逐步剖析了Optional的源碼、原理和使用。此時再回頭看最初的示例是不是已經豁然開朗了?

關于Optional的學習其實把握住本質就可以了:Optional本質上是一個對象的容器,將對象存入其中之后,可以幫我們做一些非空判斷、取值、過濾、轉換等操作。

理解了本質,如果哪個API的使用不確定,看一下源碼就可以了。此時,可以愉快的繼續看源碼了~  

 

責任編輯:武曉燕 來源: 程序新視界
相關推薦

2009-04-09 08:51:40

Windows 7微軟操作系統

2010-03-31 15:35:35

云計算

2020-09-27 06:47:20

5G網絡運營商

2015-09-18 16:11:04

圖標桌面環境KDE

2015-07-14 10:18:42

Windows 10正式版

2023-06-06 07:41:00

Reacthook

2023-06-02 07:04:24

宏碁映泰技嘉

2024-02-20 12:30:36

AI模型

2018-10-18 09:58:41

物聯網IOT數字化

2023-02-06 14:41:13

量子模型

2022-12-27 14:45:55

量子計算

2013-08-20 15:27:59

Linux操作系統

2018-08-21 05:12:10

2017-02-17 07:46:29

2024-01-02 07:34:38

CentOSLinuxRedhat

2012-03-17 21:45:02

JavaScript

2024-02-22 16:50:50

2023-10-19 15:25:40

2018-07-27 16:58:07

人工智能機器學習機器人

2023-11-03 18:00:18

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久av网站 | 九九综合九九 | 成人免费视频网站在线观看 | 亚洲成人免费视频在线 | 久久一本 | 国产成人精品区一区二区不卡 | 日韩二区 | 日韩欧美三级电影 | 久久夜视频 | 中文字幕一区二区三区乱码在线 | 国产精品视频一区二区三区四区国 | 91操操操 | 久久精品69 | 国产在线一区二区三区 | www.久久久久久久久久久 | 精品视频在线观看 | 久久久久久久久久一区二区 | 国产91丝袜在线播放 | 九色 在线 | 久久久日韩精品一区二区三区 | 一区二区三区免费网站 | 亚洲国产精品99久久久久久久久 | 亚洲欧美视频一区 | 免费一级黄色录像 | 91免费在线 | 蜜桃臀av一区二区三区 | 欧美日韩国产高清视频 | 国产女人叫床高潮大片免费 | 国产亚洲精品91 | 午夜久久久久久久久久一区二区 | 欧美精品在线看 | 中文字幕在线观看 | 99re| av在线免费观看网站 | 欧美自拍日韩 | 99免费在线观看视频 | 成人欧美一区二区三区黑人孕妇 | 国产精品一区二区三区四区 | 黄色成人国产 | 97免费在线观看视频 | 国产精品1区|