溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何使用Nacos中的Optional

發(fā)布時(shí)間:2021-10-11 17:43:01 來(lái)源:億速云 閱讀:202 作者:iii 欄目:編程語(yǔ)言

本篇內(nèi)容主要講解“如何使用Nacos中的Optional”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“如何使用Nacos中的Optional”吧!

Nacos中的Optional使用

在Nacos中有這樣一個(gè)接口ConsistencyService,用來(lái)定義一致性服務(wù)的,其中的一個(gè)方法返回的類型便是Optional:

/**  * Get the error message of the consistency protocol.  *  * @return the consistency protocol error message.  */ Optional<String> getErrorMsg();

如果你對(duì)Optional不了解,看到這里可能就會(huì)有點(diǎn)蒙。那我們來(lái)看看Nacos是怎么使用Optional的。在上述接口的一個(gè)實(shí)現(xiàn)類PersistentServiceProcessor中是如此實(shí)現(xiàn)的:

@Override public Optional<String> getErrorMsg() {     String errorMsg;     if (hasLeader && hasError) {         errorMsg = "The raft peer is in error: " + jRaftErrorMsg;     } else if (hasLeader && !hasError) {         errorMsg = null;     } else if (!hasLeader && hasError) {         errorMsg = "Could not find leader! And the raft peer is in error: " + jRaftErrorMsg;     } else {         errorMsg = "Could not find leader!";     }     return Optional.ofNullable(errorMsg); }

也就是根據(jù)hasLeader和hasError兩個(gè)變量來(lái)確定返回的errorMsg信息是什么。最后將errorMsg封裝到Optional中進(jìn)行返回。

下面再看看方法getErrorMsg是如何被調(diào)用的:

String errorMsg; if (ephemeralConsistencyService.getErrorMsg().isPresent()         && persistentConsistencyService.getErrorMsg().isPresent()) {     errorMsg = "'" + ephemeralConsistencyService.getErrorMsg().get() + "' in Distro protocol and '"             + persistentConsistencyService.getErrorMsg().get() + "' in jRaft protocol"; }

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

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

Optional的數(shù)據(jù)結(jié)構(gòu)

面對(duì)新生事物我們都會(huì)有些許畏懼,當(dāng)我們庖丁解牛似的將其拆分之后,了解其實(shí)現(xiàn)原理,就沒(méi)那么恐怖了。

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

public final class Optional<T> {     /**      * Common instance for {@code empty()}.      */     private static final Optional<?> EMPTY = new Optional<>(null);      /**      * If non-null, the value; if null, indicates no value is present      */     private final T value;     // ... }

其中EMPTY變量表示的是如果創(chuàng)建一個(gè)空的Optional實(shí)例,很顯然,在加載時(shí)已經(jīng)初始化了。而value是用來(lái)存儲(chǔ)我們業(yè)務(wù)中真正使用的對(duì)象,比如上面的errorMsg就是存儲(chǔ)在這里。

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

看到這里,是不是感覺(jué)Optional并沒(méi)那么神秘了?是不是也沒(méi)那么恐懼了?

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

if( user != null){     Address address = user.getAddress();     if(address != null){         String province = address.getProvince();     } }

原來(lái)是為了封裝,原來(lái)是為了更優(yōu)雅的代碼,這不正是我們有志向的程序員所追求的么。

如何將對(duì)象存入Optional容器中

這么我們就姑且稱Optional為Optional容器了,下面就看看如何將對(duì)象放入Optional當(dāng)中。

看到上面的EMPTY初始化時(shí)調(diào)用了構(gòu)造方法,傳入null值,我們是否也可以這樣來(lái)封裝對(duì)象?好像不行,來(lái)看一下Optional的構(gòu)造方法:

private Optional() {     this.value = null; }  private Optional(T value) {     this.value = Objects.requireNonNull(value); }

存在的兩個(gè)構(gòu)造方法都是private的,看來(lái)只能通過(guò)Optional提供的其他方法來(lái)封裝對(duì)象了,通常有以下方式。

empty方法

empty方法源碼如下:

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

簡(jiǎn)單直接,直接強(qiáng)轉(zhuǎn)EMPTY對(duì)象。

of方法

of方法源碼如下:

public static <T> T requireNonNull(T obj) {     if (obj == null)         throw new NullPointerException();     return obj; }

注釋上說(shuō)是為非null的值創(chuàng)建一個(gè)Optional,而非null的是通過(guò)上面構(gòu)造方法中的Objects.requireNonNull方法來(lái)檢查的:

public static <T> T requireNonNull(T obj) {     if (obj == null)         throw new NullPointerException();     return obj; }

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

ofNullable方法

ofNullable方法源碼如下:

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

ofNullable為指定的值創(chuàng)建一個(gè)Optional,如果指定的值為null,則返回一個(gè)空的Optional。也就是說(shuō)此方法支持對(duì)象的null與非null構(gòu)造。

回顧一下:Optional構(gòu)造方法私有,不能被外部調(diào)用;empty方法創(chuàng)建空的Optional、of方法創(chuàng)建非空的Optional、ofNullable將兩者結(jié)合。是不是so  easy?

此時(shí),有朋友可能會(huì)問(wèn),相對(duì)于ofNullable方法,of方法存在的意義是什么?在運(yùn)行過(guò)程中,如果不想隱藏NullPointerException,就是說(shuō)如果出現(xiàn)null則要立即報(bào)告,這時(shí)就用Of函數(shù)。另外就是已經(jīng)明確知道value不會(huì)為null的時(shí)候也可以使用。

判斷對(duì)象是否存在

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

isPresent方法

上述問(wèn)題,答案是:可以的。對(duì)應(yīng)的方法就是isPresent:

public boolean isPresent() {     return value != null; }

實(shí)現(xiàn)簡(jiǎn)單直白,相當(dāng)于將obj != null的判斷進(jìn)行了封裝。該對(duì)象如果存在,方法返回true,否則返回false。

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

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

如果Optional實(shí)例有值則為其調(diào)用consumer,否則不做處理??梢灾苯訉ambda表達(dá)式傳遞給該方法,代碼更加簡(jiǎn)潔、直觀。

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

獲取值

當(dāng)我們判斷Optional中有值時(shí)便可以進(jìn)行獲取了,像Nacos中使用的那樣,調(diào)用get方法:

public T get() {     if (value == null) {         throw new NoSuchElementException("No value present");     }     return value; }

很顯然,如果value值為null,則該方法會(huì)拋出NoSuchElementException異常。這也是為什么我們?cè)谑褂脮r(shí)要先調(diào)用isPresent方法來(lái)判斷一下value值是否存在了。此處的設(shè)計(jì)稍微與初衷相悖。

看一下使用示例:

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

設(shè)置(或獲取)默認(rèn)值

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

orElse方法

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

public T orElse(T other) {     return value != null ? value : other; }

可以看到是get方法的加強(qiáng)版,get方法如果值為null直接拋異常,orElse則不,如果只為null,返回你傳入進(jìn)來(lái)的參數(shù)值。

使用示例:

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

orElseGet方法

orElseGet:orElseGet與orElse方法類似,區(qū)別在于得到的默認(rèn)值。orElse方法將傳入的對(duì)象作為默認(rèn)值,orElseGet方法可以接受Supplier接口的實(shí)現(xiàn)用來(lái)生成默認(rèn)值:

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

當(dāng)value為null時(shí)orElse直接返回傳入值,orElseGet返回Supplier實(shí)現(xiàn)類中定義的值。

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

其實(shí)上面的示例可以直接優(yōu)化為orElse,因?yàn)镾upplier接口的實(shí)現(xiàn)依舊是直接返回輸入值。

orElseThrow方法

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

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

使用示例:

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

學(xué)完上述內(nèi)容,基本上已經(jīng)掌握了Optional百分之八十的功能了。同時(shí),還有兩個(gè)相對(duì)高級(jí)點(diǎn)的功能:過(guò)濾值和轉(zhuǎn)換值。

filter方法過(guò)濾值

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

當(dāng)然,也可以通過(guò)Optional提供的filter來(lái)進(jìn)行取出前的過(guò)濾:

public Optional<T> filter(Predicate<? super T> predicate) {     Objects.requireNonNull(predicate);     if (!isPresent())         return this;     else         return predicate.test(value) ? this : empty(); }

filter方法的參數(shù)類型為Predicate類型,可以將Lambda表達(dá)式傳遞給該方法作為條件,如果表達(dá)式的結(jié)果為false,則返回一個(gè)EMPTY的Optional對(duì)象,否則返回經(jīng)過(guò)過(guò)濾的Optional對(duì)象。

使用示例:

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

map方法轉(zhuǎn)換值

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

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

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

map方法的參數(shù)類型為Function,會(huì)調(diào)用Function的apply方法對(duì)對(duì)Optional中的值進(jìn)行處理。如果Optional中的值本身就為null,則返回空,否則返回處理過(guò)后的值。

示例:

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

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

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

可以看出,它與map方法的實(shí)現(xiàn)非常像,不同的是傳入的參數(shù)類型,map函數(shù)所接受的入?yún)㈩愋蜑镕unction,而flapMap的入?yún)㈩愋蜑镕unction>。

flapMap示例如下:

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

對(duì)照map的示例,可以看出在flatMap中對(duì)結(jié)果進(jìn)行了一次Optional#of的操作。

到此,相信大家對(duì)“如何使用Nacos中的Optional”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI