Optional 優(yōu)雅的避免NPE

參考的博客寫在前面吧,感覺(jué)沒(méi)他們寫的好

【java8新特性】Optional詳解 - 簡(jiǎn)書 (jianshu.com)

理解、學(xué)習(xí)與使用 Java 中的 Optional - 張伯雨 - 博客園 (cnblogs.com)

一、為什么要引入Optional

? 下面這代碼,我們?cè)L問(wèn)任何對(duì)象或?qū)傩?,都有可能因?yàn)槟硞€(gè)對(duì)象為null導(dǎo)致NullPointerException

String result = school.getStudent().getA();

? 為了解決NullPointException(NPE)問(wèn)題,一般的我們采用逐個(gè)判斷是否為null再繼續(xù)下面的業(yè)務(wù)邏輯,如果需要判斷的對(duì)象很多,代碼看起來(lái)很多,很冗余。如下:

原先的避免NPE的方式

// 判斷每一層是否為空
if(school==null){
    result = "error";
}else if(school.getStudent()==null){
    result = "error";
}else if(school.getStudent().getA()==null){
    result = "error";
}else {
    result = school.getStudent().getA();
}
System.out.println(result);

使用Optional的方式

//直接構(gòu)造Optional并返回想要的結(jié)果
String result = Optional.ofNullable(school)
                        .map(School::getStudent)
                        .map(Student::getA)
                        .orElse("error");
System.out.println(result);

? 對(duì)比以上兩種方式,可以明顯的看出使用Optional的代碼更加簡(jiǎn)潔,不羅嗦,在orElse中可以直接將特殊情況返回,下面介紹Optional的具體用法。

二、Optional的使用

? 先看看Optional的部分源碼:

    private static final Optional<?> EMPTY = new Optional<>();

    private final T value;

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

    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }

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

    public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }

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

這里可以看出,Optional的構(gòu)造函數(shù)都是私有,因此類外部不能顯示的使用new Optional()的方式來(lái)創(chuàng)建Optional對(duì)象,但是Optional類提供了三個(gè)靜態(tài)方法來(lái)創(chuàng)建Optional對(duì)象,示例如下:

empty() 空的Optional對(duì)象

of(T value) 非空的Optional對(duì)象

ofNullable(T value) 允許空的Optional對(duì)象

Optional<String> optStr = Optional.empty(); // 空
Student student = new Student();
Optional<Student> optStudent = Optional.of(student); // 非空
Optional<Student> optClass = Optional.ofNullable(student);// 可以空

構(gòu)建了Optional對(duì)象,下面來(lái)看看怎么使用Optional對(duì)象的接口,直接推薦兩種常用的使用方式:

第一種是使用orElse()接口,如果不為空,直接返回結(jié)果,為空返回orElse()中的內(nèi)容。看看源碼先:

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

再來(lái)看看orElse()的例子,將str包裝成Optional對(duì)象后,通過(guò)orElse()返回值。

String str = "hello";
String str1 = Optional.ofNullable(str).orElse("unknown");

第二種是使用ifPresent()接口,不為空則直接執(zhí)行ifpresent()內(nèi)的函數(shù),省去判空的步驟。看看源碼先:

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

源碼內(nèi)提到ifPresent()方法接受一個(gè)Consumer對(duì)象(消費(fèi)函數(shù)),如果包裝對(duì)象的值非空,運(yùn)行Consumer對(duì)象的accept()方法,(我的理解就是一個(gè)無(wú)返回值的函數(shù)而已),看看栗子:

Optional.ofNullable(student)
        .ifPresent( u ->  System.out.println("The student name is : " + u.getName()));

三、Optional的其他方法列舉

  • get()方法

    ? 直接放回包裝對(duì)象的實(shí)際值,為null拋出異常

  • isPresent()方法

    ? 判斷包裝對(duì)象是否為空

    特別說(shuō)明的是,get()方法并沒(méi)有直接對(duì)空對(duì)象有所處理,所以直接使用,仍然會(huì)有NPE問(wèn)題,于是,就有人想到:那我先用isPresent()先判空,再取值不就好了,于是就產(chǎn)生了如下的憨憨的代碼:

    Optional<Student> studentOpt = Optional.ofNullable(student);
    if(isPresent(studentOpt)){
        String str = student.get();
    }else{
        String str = "unknown";
    }
    

    上面的代碼違背了Optional的初衷,應(yīng)使用orElse()方法改為如下:

    String str = Optional.ofNullable(student).orElse("unknown");
    
  • map()方法

    ? 將Optional中的包裝對(duì)象經(jīng)過(guò)函數(shù)運(yùn)算后,并包裝成新的Optional對(duì)象

    Optional<String> nameOpt = Optional.ofNullable(student).map(u -> u.getName());
    

    ? 或?qū)懗上旅娴母袷?,更加?jiǎn)潔

    Optional<String> nameOpt = Optional.ofNullable(student).map(Student::getName);
    

    ? map()鏈?zhǔn)秸{(diào)用,配合上orElse()就完成了文初的效果:

    String result = Optional.ofNullable(school)
                          .map(School::getStudent)
                          .map(Student::getA)
                          .orElse("error");
    System.out.println(result);
    

?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容