欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java新特性之Optional類超詳細(xì)介紹

 更新時(shí)間:2023年07月25日 09:54:45   作者:栗箏i  
這篇文章主要給大家介紹了關(guān)于Java新特性之Optional類超詳細(xì)介紹的相關(guān)資料,Java8中的Optional類是一個(gè)容器對(duì)象,可以包含null或非null值,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下

前言

Optional 類是 Java 8 才引入的,Optional 是個(gè)容器,它可以保存類型 T 的值,或者僅僅保存 null。Optional 提供了很多方法,這樣我們就不用顯式進(jìn)行空值檢測(cè)。Optional 類的引入很好的解決空指針異常。

Java 8 引入 Optional 類,用來解決 NullPointerException。 Optional 代替 if…else 解決空指針問題,使代碼更加簡(jiǎn)潔。

1、Optional類概述

1.1、Optional類介紹

Optional 類是 Java 8 才引入的,Optional 是個(gè)容器,它可以保存類型 T 的值,或者僅僅保存 null。Optional 提供了很多方法,這樣我們就不用顯式進(jìn)行空值檢測(cè)。Optional 類的引入很好的解決空指針異常。

Java 8 引入 Optional 類,用來解決 NullPointerException。 Optional 代替 if…else 解決空指針問題,使代碼更加簡(jiǎn)潔。

1.2、Java8之前的空指針異常判斷

Java 在使用對(duì)象過程中,訪問任何方法或?qū)傩远伎赡軐?dǎo)致 NullPointerException:

例如我們通過以下方法,獲取存在 student 對(duì)象中的 Age 值。

        public String getIsocode (Student student){
            return student.getAge();
        }

在這樣的示例中,如果我們想要避免由 studentstudent.age 為空而導(dǎo)致的空指針問題,我們就需要采用防御式檢查減少 NullPointerException(在訪問每一個(gè)值之前對(duì)其進(jìn)行明確地檢查):

       public String getIsocode (Student student){
            if (null == student) {
                // doSomething
                return "Unknown";
            }
            if (null = student.getAge()) {
                // doSomething
                return "Unknown";
            }
            return student.getAge();
        }

然而,這種方案并不是很理想,因?yàn)闉榇藭?huì)多出多個(gè)不同的退出點(diǎn)(return),使得代碼維護(hù)變得艱難,之后每個(gè)可能的 null 檢查都會(huì)新增一個(gè)退出點(diǎn)。

為了簡(jiǎn)化這個(gè)過程,我們來看看用 Optional 類是怎么做的。

1.3、Java8之后Optional的使用

當(dāng)需要判斷的量多時(shí),此時(shí)的這些判斷語句可能會(huì)導(dǎo)致代碼臃腫冗余,為此 Java8 特意推出了 Optional 類來幫助我們?nèi)ヌ幚砜罩羔槷惓!?/p>

下面是 Optional 的一些基本用法:

@Data
public class Student {
    private Integer age;
}
---
public class Test {
    public static void main(String[] args) {
        // 假設(shè) student 這個(gè)對(duì)象從數(shù)據(jù)庫(kù)中查出的
        Student student = getStudent();
        // 創(chuàng)建一個(gè)可接受 null 的 Optiona l類
        Optional<Student> optional = Optional.ofNullable(student);
        // 用法1:獲取 student 對(duì)象中的某個(gè)值,如果不存在的話則取默認(rèn)值(不具有短路作用)
        Integer a1 = optional.map(Student::getAge).orElse(20));
        // 用法2:獲取 student 對(duì)象中的某個(gè)值,如果不存在的話則取默認(rèn)值(具有短路作用,因?yàn)槭菓屑虞d)
        Integer a2 = optional.map(Student::getAge).orElseGet(() -> Integer.MAX_VALUE);
      	// 用法3:判斷對(duì)象是否存在,不存在則拋出異常
        optional.orElseThrow(() -> new RuntimeException("student不存在!"));
      	// 用法4:判斷對(duì)象是否存在,存在的話對(duì)對(duì)象進(jìn)行操作,例如給對(duì)象賦初始值
        optional.ifPresent(o -> o.setAge(18));
      	// 用法5:對(duì)象存在時(shí),且年齡滿足一定條件容器才會(huì)繼續(xù)保存這對(duì)象,否則將會(huì)剔除
        optional.filter(o -> o.getAge() > 10);
    }
}

2、Optional類使用

2.1、Optional類常用方法總結(jié)

方法描述
empty返回一個(gè)空的 Optional 實(shí)例
filter如果值存在并且滿足提供的謂詞,就返回包含該值的 Optional 對(duì)象;否則返回一個(gè)空的 Optional 對(duì)象
flatMap如果值存在,就對(duì)該值執(zhí)行提供的 mapping 函數(shù)調(diào)用,返回一個(gè) Optional 類型的值,否則就返回一個(gè)空的 Optional 對(duì)象
get如果該值存在,將該值用 Optional 封裝返回,否則拋出一個(gè) NoSuchElementException 異常
ifPresent如果值存在,就執(zhí)行使用該值的方法調(diào)用,否則什么也不做
isPresent如果值存在就返回 true,否則返回 false
map如果值存在,就對(duì)該值執(zhí)行提供的mapping 函數(shù)調(diào)用
of將指定值用 Optional 封裝之后返回,如果該值為 null,則拋出一個(gè) NullPointerException 異常
ofNullable將指定值用 Optional 封裝之后返回,如果該值為 null,則返回一個(gè)空的 Optional 對(duì)象
orElse如果有值則將其返回,否則返回一個(gè)默認(rèn)值
orElseGet如果有值則將其返回,否則返回一個(gè)由指定的 Supplier 接口生成的值
orElseThrow如果有值則將其返回,否則拋出一個(gè)由指定的 Supplier 接口生成的異常

2.2、Optional對(duì)象創(chuàng)建

2.2.1、Optional.empty()方法

使用 Optional.empty() 方法聲明一個(gè)空的 Optional:

// 通過靜態(tài)工廠方法 Optional.empty(),創(chuàng)建一個(gè)空的 Optional 對(duì)象
Optional<Student> optStudent = Optional.empty();

2.2.2、Optional.of(T t)方法

使用 Optional.of(T t) 方法創(chuàng)建一個(gè)包含非空值的 Optional 對(duì)象 (不推薦):

// 靜態(tài)工廠方法 Optional.of(T t),依據(jù)一個(gè)非空值創(chuàng)建一個(gè) Optional 對(duì)象
Optional<Student> optStudent = Optional.of(student);

如果 student 為 null,這段代碼會(huì)立即拋出一個(gè) NullPointerException,而不是等到訪問 student 的屬性值時(shí)才返回一個(gè)錯(cuò)誤。

2.2.3、Optional.ofNullable(T t)方法

使用 Optional.ofNullable(T t) 方法創(chuàng)建一個(gè)包含可能為空的值的 Optional 對(duì)象 (推薦):

// 用靜態(tài)工廠方法 Optional.ofNullable(T t),你可以創(chuàng)建一個(gè)允許 null 值的 Optional 對(duì)象
Optional<Student> optStudent = Optional.ofNullable(student);

2.3、Optional對(duì)象獲取

2.3.1、get()方法

get() 方法,如果變量存在,它直接返回封裝的變量值,否則就拋出一個(gè) NoSuchElementException 異常,不推薦使用:

optional.map(Student::getAge).get()

2.3.2、orElse(T other)方法

orElse(T other) 方法,它允許你在 Optional 對(duì)象不包含值時(shí)提供一個(gè)默認(rèn)值:

optional.map(Student::getAge).orElse(20));

2.3.3、orElseGet(Supplier<? extends T> other)方法

orElseGet(Supplier<? extends T> other) 方法,它是 orElse 方法的延遲調(diào)用版,Supplier 方法只有在 Optional 對(duì)象不含值時(shí)才執(zhí)行調(diào)用(懶加載):

optional.map(Student::getAge).orElseGet(() -> Integer.MAX_VALUE);

2.3.4、orElseThrow(Supplier<? extends X> exceptionSupplier)方法

orElseThrow(Supplier<? extends X> exceptionSupplier) 方法,它和 get 方法非常類似,它們?cè)庥?Optional 對(duì)象為空時(shí)都會(huì)拋出一個(gè)異常,但是使用 orElseThrow 可以定制希望拋出的異常類型:

optional.orElseThrow(() -> new RuntimeException("student不存在!"));

2.3.5、ifPresent(Consumer<? super T> consumer)方法

ifPresent(Consumer<? super T> consumer) 方法,它讓能在變量值存在時(shí)執(zhí)行一個(gè)作為參數(shù)傳入的方法,否則就不進(jìn)行任何操作:

optional.ifPresent(o -> o.setAge(18));

2.4、Optional對(duì)象中值的提取和轉(zhuǎn)換

2.4.1、map()方法

map() 方法,如果值存在,就對(duì)該值執(zhí)行提供的 mapping 函數(shù)調(diào)用,如果值不存在,則返回一個(gè)空的 Optional 對(duì)象。

引入 Optional 以前:

String name = null;
    if(insurance != null){
        name = insurance.getName();
    }

引入 Optional 以后:

Optional<String> name = Optional.ofNullable(insurance).map(Insurance::getName);

Optional 的 map 方法和 Java 8 中 Stream 的 map 方法相差無幾。

2.4.2、flatMap()方法

flatMap() 方法,對(duì)于嵌套式的 Optiona 結(jié)構(gòu),我們應(yīng)該使用 flatMap 方法,將兩層的 Optional 合并成一個(gè)。

我們?cè)囍貥?gòu)以下代碼:

  public String getCarInsuranceName(Person person) {
      return person.getCar().getInsurance().getName();
  }

由于我們剛剛學(xué)習(xí)了如何使用 map,我們的第一反應(yīng)可能是我們可以利用 map 重寫之前的代碼:

  Optional<Person> optPerson = Optional.of(person);
      Optional<String> name =
          optPerson.map(Person::getCar)
                   .map(Car::getInsurance)
                   .map(Insurance::getName);

不幸的是,這段代碼無法通過編譯。為什么呢? optPerson 是 Optional<Person> 類型的 變量, 調(diào)用 map 方法應(yīng)該沒有問題。但 getCar 返回的是一個(gè) Optional<Car> 類型的對(duì)象,這意味著 map 操作的結(jié)果是一個(gè) Optional<Optional<Car>> 類型的對(duì)象。因此,它對(duì) getInsurance 的調(diào)用是非法的。

下面應(yīng)用 map 和 flatMap 對(duì)上述示例進(jìn)行重寫:

  public String getCarInsuranceName(Optional<Person> person) { 
      return person.flatMap(Person::getCar)
                       .flatMap(Car::getInsurance)
                       .map(Insurance::getName)
                       .orElse("Unknown"); // 如果Optional的結(jié)果 值為空設(shè)置默認(rèn)值
  }

2.5、Optional對(duì)象其他方法

2.5.1、isPresent()方法

可以使用 isPresent() 方法檢查 Optional 對(duì)象是否包含非空值,例如:

Optional<String> optional = Optional.of("Hello World"); 
if (optional.isPresent()) { 
    System.out.println(optional.get()); 
}

2.5.2、filter()方法

filter() 方法接受一個(gè)謂詞作為參數(shù)。如果 Optional 對(duì)象的值存在,并且它符合謂詞的條件,filter 方法就返回其值,否則它就返回一個(gè)空的 Optional 對(duì)象。

比如,你可能需要檢查保險(xiǎn)公司的名稱是否為 “Cambridge-Insurance”。

Insurance insurance = ...;
	if(insurance != null && "CambridgeInsurance".equals(insurance.getName())){
			System.out.println("ok");
  }

使用 Optional 對(duì)象的 filter 方法,這段代碼可以重構(gòu)如下:

Optional<Insurance> optInsurance = ...;
optInsurance.filter(insurance -> "CambridgeInsurance".equals(insurance.getName()))
            .ifPresent(x -> System.out.println("ok"));

3、Optional注意事項(xiàng)

3.1、Optional的序列化問題

由于 Optiona l類設(shè)計(jì)時(shí)就沒特別考慮將其作為類的字段使用,所以它也并未實(shí)現(xiàn) Serializable 接口。由于這個(gè)原因,如果你的應(yīng)用使用了某些要求序列化的庫(kù)或者框架,在域模型中使用Optional,有可能引發(fā)應(yīng)用程序故障。

然而,我們相信,通過前面的介紹,我們已經(jīng)看到用 Optional 聲明域模型中的某些類型是個(gè)不錯(cuò)的主意,尤其是你需要遍歷有可能全部或部分為空,或者可能不存在的對(duì)象時(shí)。如果你一定要實(shí)現(xiàn)序列化的域模型,作為替代方案, 我們建議你像下面這個(gè)例子那樣,提供一個(gè)能訪問聲明為 Optional、變量值可能缺失的接口,代碼清單如下:

public class Person {
    private Car car;
    public Optional<Car> getCarAsOptional() {
      return Optional.ofNullable(car);
    } 
}

3.2、避免使用基礎(chǔ)類型的 Optional 對(duì)象

Optional 提供了的一些基礎(chǔ)類型 —— OptionalInt、OptionalLong 以及 OptionalDouble ,但不推薦大家使用基礎(chǔ)類型的 Optional,因?yàn)榛A(chǔ)類型的 Optional 不支持 map、 flatMap 以及 filter 方法,而這些卻是 Optional 類常用的方法??梢允褂?Optional<Int>, Optional<Long>, Optional<Double> 等替代。3. orElse方法的使用

3.3、orElse方法的使用

orElse 中調(diào)用的方法一直都會(huì)被執(zhí)行,orElseGet 方法只有在 Optional 對(duì)象不含值時(shí)才會(huì)被調(diào)用,所以使用 orElse 方法時(shí)需要謹(jǐn)慎, 以免誤執(zhí)行某些不被預(yù)期的操作。此種情況下,可使用 orElseGet 方法代替它。

總結(jié)

到此這篇關(guān)于Java新特性之Optional類超詳細(xì)介紹的文章就介紹到這了,更多相關(guān)Java新特性O(shè)ptional類內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論