最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java8中Optional類(lèi)的使用說(shuō)明

 更新時(shí)間:2021年11月03日 14:53:39   作者:永動(dòng)的圖靈機(jī)  
Optional類(lèi)主要解決的問(wèn)題是臭名昭著的空指針異常(NullPointerException),每個(gè)Java程序員都非常了解的異常,這篇文章主要給大家介紹了關(guān)于Java8中Optional類(lèi)使用的相關(guān)資料,需要的朋友可以參考下

簡(jiǎn)介

optional類(lèi)是java8中引入的針對(duì)NPE問(wèn)題的一種優(yōu)美處理方式,源碼作者也希望以此替代null。

歷史

1965年,英國(guó)一位名為T(mén)ony Hoare的計(jì)算機(jī)科學(xué)家在設(shè)計(jì)ALGOL W語(yǔ)言時(shí)提出了null引用的想法。Hoare選擇null引用這種方式,“只是因?yàn)檫@種方法實(shí)現(xiàn)起來(lái)非常容易”。很多年后,他開(kāi)始為自己曾經(jīng)做過(guò)這樣的決定而后悔不迭,把它稱為“我價(jià)值百萬(wàn)的重大失誤”。我們已經(jīng)看到它帶來(lái)的后果——程序員對(duì)對(duì)象的字段進(jìn)行檢查,判斷它的值是否為期望的格式,最終卻發(fā)現(xiàn)我們查看的并不是一個(gè)對(duì)象,而是一個(gè)空指針,它會(huì)立即拋出一個(gè)讓人厭煩的NullPointerException異常[1]。

null帶來(lái)的種種問(wèn)題

  • 錯(cuò)誤之源。

NullPointerException是目前Java程序開(kāi)發(fā)中最典型的異常。

  • 代碼膨脹。

它讓你的代碼充斥著深度嵌套的null檢查,代碼的可讀性糟糕透頂。

  • 自身是毫無(wú)意義的。

null自身沒(méi)有任何的語(yǔ)義,尤其是,它代表的是在靜態(tài)類(lèi)型語(yǔ)言中以一種錯(cuò)誤的方式對(duì)缺失變量值的建模。

  • 破壞了Java的哲學(xué)。

Java一直試圖避免讓程序員意識(shí)到指針的存在,唯一的例外是:null指針。

  • 在Java的類(lèi)型系統(tǒng)上開(kāi)了個(gè)口子。

null并不屬于任何類(lèi)型,這意味著它可以被賦值給任意引用類(lèi)型的變量。這會(huì)導(dǎo)致問(wèn)題,原因是當(dāng)這個(gè)變量被傳遞到系統(tǒng)中的另一個(gè)部分后,你將無(wú)法獲知這個(gè)null變量最初的賦值到底是什么類(lèi)型。

方案

汲取Haskell和Scala的靈感,Java 8中引入了一個(gè)新的類(lèi)java.util.Optional<T>。這是一個(gè)封裝Optional值的類(lèi)。舉例來(lái)說(shuō),使用新的類(lèi)意味著,如果你知道一個(gè)人可能有學(xué)校也可能沒(méi)有,那么Student類(lèi)內(nèi)部的school變量就不應(yīng)該聲明為Schoold,遭遇某學(xué)生沒(méi)有學(xué)校時(shí)把null引用賦值給它,而是應(yīng)該像本篇那樣直接將其聲明為Optional<School>類(lèi)型。

場(chǎng)景引入

首先我們引入一個(gè)常見(jiàn)的兩個(gè)場(chǎng)景

/**
 * >1 引入,常規(guī)判斷一個(gè)學(xué)生的學(xué)校是不是公立學(xué)校,判斷是否成年
 */
public static boolean checkIsPublicV1(Student student) {
    if (student != null) {
        School school = student.getSchool();
        if (school != null) {
            return school.isPublicFlag();
        }
    }
    throw new RuntimeException("參數(shù)異常");
}

public static String getAdultV1(Student student) {
    if (student != null) {
        int age = student.getAge();
        if (age > 18) {
            return student.getName();
        }
    }
    return "無(wú)";
}

上述方式是我們常見(jiàn)的判讀流程,optional就是針對(duì)每次空判斷導(dǎo)致的代碼欣賞性問(wèn)題進(jìn)行了一套解決方案

方法說(shuō)明

構(gòu)造函數(shù)

  • Optional(T var1)

源碼

private final T value;

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

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

從源碼可知,optional的構(gòu)造器私有,不能直接創(chuàng)建,只能通過(guò)類(lèi)中的其他靜態(tài)方法創(chuàng)建,optional構(gòu)造器支持一個(gè)泛型入?yún)?,且改參?shù)不能為空

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

  • 聲明一個(gè)空的Optional: Optional<T> empty()
  • 依據(jù)一個(gè)非空值創(chuàng)建Optional: Optional<T> of(T var0)
  • 可接受null的Optional: Optional<T> ofNullable(T var0)

源碼

empty()源碼

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

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

public static <T> Optional<T> empty() {
    Optional var0 = EMPTY;
    return var0;
}


從源碼可知,optional類(lèi)中維護(hù)了一個(gè)null值的對(duì)象,使用empty靜態(tài)方法即可返回該空值對(duì)象

of(T var0)源碼

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

返回常見(jiàn)的有參構(gòu)造對(duì)象,注意由于構(gòu)造器要求入?yún)⒉荒転榭?,因此of方法的入?yún)榭盏脑挘廊粫?huì)報(bào)NPE異常

ofNullable(T var0)源碼

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

這個(gè)方法是對(duì)of方法的補(bǔ)強(qiáng),當(dāng)ofNullable方法的入?yún)⒉粸榭帐钦7祷貥?gòu)造對(duì)象,當(dāng)入?yún)榭諘r(shí),返回一個(gè)空值的optional對(duì)象,而不會(huì)拋出異常。

ofNullable方法大部分場(chǎng)景優(yōu)于of的使用。

null引用和Optional.empty()有什么本質(zhì)的區(qū)別嗎?從語(yǔ)義上,你可以把它們當(dāng)作一回事兒,但是實(shí)際中它們之間的差別非常大:如果你嘗試解引用一個(gè)null,一定會(huì)觸發(fā)NullPointerException,不過(guò)使用Optional.empty()就完全沒(méi)事兒,它是Op-tional類(lèi)的一個(gè)有效對(duì)象,多種場(chǎng)景都能調(diào)用,非常有用。

舉例

public static void testOptionalBuild() {
    // 1. 無(wú)法直接new 'Optional()' has private access in 'java.util.Optional'
    // Optional<School> school = new Optional<>();

    // 2. of構(gòu)建非空和空對(duì)象(NullPointerException)
    /*Optional<String> o1 = Optional.of("test");
    System.out.println(o1);
    Optional<Object> o2 = Optional.of(null);
    System.out.println(o2);*/

    // 3. ofNullable構(gòu)建非空和空對(duì)象(Optional.empty)
    /*Optional<String> o3 = Optional.ofNullable("test");
    System.out.println(o3);
    Optional<Object> o4 = Optional.ofNullable(null);
    System.out.println(o4);*/
}

使用map從Optional對(duì)象中提取和轉(zhuǎn)換值

  • Optional<U> map(Function<? super T, ? extends U> var1)

源碼

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

當(dāng)optional包裹的值為空時(shí)直接放回空對(duì)象,否則執(zhí)行入?yún)⒅械腇unction.apply方法

使用flatMap鏈接Optional對(duì)象

  • Optional<U> flatMap(Function<? super T, Optional<U>> var1)

源碼

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

與map幾乎一致。注意的是,入?yún)⒌腇unction.apply方法中,返回類(lèi)型為optional類(lèi)型

舉例

public static void testOptionalMap() {
    Student student1 = getDefaultStudent();
    Student student2 = getBackStudent();
    // map
    String school1 = Optional.ofNullable(student1).map(i -> i.getName()).orElse("無(wú)名");
    String school2 = Optional.ofNullable(student2).map(i -> i.getName()).orElse("無(wú)名");
    System.out.println("school1: " + school1 + "| school2: " + school2);
    // flapMap 鏈?zhǔn)?
    String school3 = Optional.ofNullable(getOptionalStudent()).flatMap(i -> getOptionalStudent()).flatMap(i->i.getSchool()).map(i->i.getSchoolName()).orElse("沒(méi)上大學(xué)");
    System.out.println("school3: " + school3);
}

默認(rèn)行為及解引用Optional對(duì)象1

  • T orElse(T var1)
  • T orElseGet(Supplier<? extends T> var1)
  • T orElseThrow(Supplier<? extends X> var1)

注:這三個(gè)方法方法不是靜態(tài)方法,因此需要通過(guò)實(shí)例對(duì)象調(diào)用,一般跟在方法ofNullable后用于處理空值或返回值

源碼

orElse源碼

public T orElse(T var1) {
    return this.value != null ? this.value : var1;
}

當(dāng)optional中的包裹值不為空時(shí)返回包裹的值,若為空則返回orElse中的入?yún)⒅?/p>

orElseGet源碼

public T orElseGet(Supplier<? extends T> var1) {
    return this.value != null ? this.value : var1.get();
}
public T get() {
    if (this.value == null) {
        throw new NoSuchElementException("No value present");
    } else {
        return this.value;
    }
}

與上個(gè)方法類(lèi)似,當(dāng)optional中的包裹值不為空時(shí)返回包裹的值,若為空?qǐng)?zhí)行orElseGet中的Supplier方法

orElseThrow源碼

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

類(lèi)似的,當(dāng)optional中的包裹值不為空時(shí)返回包裹的值,若為空拋出orElseThrow中的Supplier.get的異常方法

舉例

public static void testOptionalOrElse() {
    // orElse
    Student stu = getDefaultStudent();
    Student backStudent = getBackStudent();
    Student realStu1 = Optional.ofNullable(stu).orElse(backStudent);
    System.out.println(realStu1);

    // orElseGet
    Student realStu2 = Optional.ofNullable(stu).orElseGet(()-> getBackStudent());
    System.out.println(realStu2);

    // orElseGet
    Student realStu3 = Optional.ofNullable(stu).orElseThrow(()-> new RuntimeException("學(xué)生不存在"));
    System.out.println(realStu3);
}

默認(rèn)行為及解引用Optional對(duì)象2

  • boolean isPresent()
  • void ifPresent(Consumer<? super T> var1)

源碼

isPresent()源碼
public boolean isPresent() {
    return this.value != null;
}

用戶判斷optional包裹的值是否為空,返回布爾值

ifPresent(Consumer var1)源碼

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

用戶處理optional包裹的值不為空時(shí),繼續(xù)處理入?yún)⒅蠧onsumer.accept的方法。類(lèi)似于 if(var!=null) {do sth}

舉例

public static void testOptionalIfPresent() {
    // isPresent()
    Student student1 = getDefaultStudent();
    Student student2 = getBackStudent();
    boolean b1 = Optional.ofNullable(student1).isPresent();
    boolean b2 = Optional.ofNullable(student2).isPresent();
    System.out.println("b1: " + b1 + "| b2: " + b2);

    // isPresent(Consumer)
    Optional.ofNullable(student2).ifPresent(i-> acceptStudent(i, LocalDate.now()));
}


使用filter剔除特定的值

  • Optional filter(Predicate<? super T> var1)

源碼

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

用于對(duì)optional對(duì)象的過(guò)濾,當(dāng)optional包裹的值不為空時(shí)返回該值,否則執(zhí)行filter入?yún)⒌腜redicate.test方法

舉例

public static void testOptionalFilter() {
    Student student1 = getDefaultStudent();
    Student student2 = getBackStudent();
    System.out.println(student1);
    System.out.println(student2);
    Student student3 = Optional.ofNullable(student1).filter(i -> i.getAge() > 18).orElse(getBackStudent());
    Student student4 = Optional.ofNullable(student2).filter(i -> i.getAge() > 18).orElse(getBackStudent());
    System.out.println(student3);
    System.out.println(student4);
}

實(shí)戰(zhàn)

關(guān)于optional類(lèi)的說(shuō)明大致已經(jīng)講完,再回到開(kāi)始的時(shí)候,提到的場(chǎng)景引入,結(jié)合optional進(jìn)行改造

/**
 * 實(shí)戰(zhàn)1
 * 針對(duì)原來(lái)的checkIsPublicV1進(jìn)行改造
 */
public static boolean checkIsPublicV2(Student student) {
    return Optional.ofNullable(student).map(i -> i.getSchool()).map(i -> i.isPublicFlag()).orElseThrow(() -> new RuntimeException("參數(shù)異常"));
}

/**
 * 實(shí)戰(zhàn)1
 * 針對(duì)原來(lái)的getAdultV1進(jìn)行改造
 */
public static String getAdultV2(Student student) {
    return Optional.ofNullable(student).filter(i->i.getAge()>18).map(i->i.getName()).orElseGet(()->getDefaultStudent().getName());
}


附:

補(bǔ)充代碼

public static void main(String[] args) {
    //逐個(gè)放開(kāi)
    // 引入
//        System.out.println(checkIsPublicV1(stu2));
//        System.out.println(getAdultV1(stu2));
    // optional方法
//        testOptionalBuild();
//        testOptionalOrElse();
//        testOptionalIfPresent();
//        testOptionalMap();
//        testOptionalFilter();
    // 實(shí)戰(zhàn)
//        System.out.println(getAdultV2(stu3));
//        System.out.println(checkIsPublicV2(stu3));
}

/**========模型數(shù)據(jù)=======**/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
static class Student {
    private String name;
    private int age;
    private School school;
}

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
static class School {
    private String schoolName;
    private boolean publicFlag;
}

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
static class StudentOpt {
    private String name;
    private int age;
    private Optional<School> school;
}

public static Student getDefaultStudent() {
    return null;
}

public static Student getBackStudent() {
    return Student.builder().name("小紅").age(19).build();
}

public static Optional<StudentOpt> getOptionalStudent() {
    return Optional.ofNullable(StudentOpt.builder().name("小莫").age(18)
            .school(Optional.ofNullable(School.builder().schoolName("藍(lán)鯨大學(xué)").publicFlag(true).build())).build());
}

public static void acceptStudent(Student stu, LocalDate date) {
    System.out.println("日期: " + date + " 新增一位學(xué)生: " + stu.getName());
}

[1] 參考自java8實(shí)戰(zhàn)

詳細(xì)源碼,請(qǐng)參考:github.com/chetwhy/clo

總結(jié)

到此這篇關(guān)于Java8中Optional類(lèi)使用的文章就介紹到這了,更多相關(guān)Java8 Optional類(lèi)使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JVM 心得分享(加載 鏈接 初始化)

    JVM 心得分享(加載 鏈接 初始化)

    下面小編就為大家?guī)?lái)一篇JVM 心得分享(加載 鏈接 初始化)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-10-10
  • 利用SpringDataJPA開(kāi)啟審計(jì)功能,自動(dòng)保存操作人操作時(shí)間

    利用SpringDataJPA開(kāi)啟審計(jì)功能,自動(dòng)保存操作人操作時(shí)間

    這篇文章主要介紹了利用SpringDataJPA開(kāi)啟審計(jì)功能,自動(dòng)保存操作人操作時(shí)間,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • java接口冪等性的實(shí)現(xiàn)方式

    java接口冪等性的實(shí)現(xiàn)方式

    本文介紹了在不同層面上實(shí)現(xiàn)Java接口冪等性的方法,包括使用冪等表、Nginx+Lua和Redis、以及SpringAOP,通過(guò)這些方法,可以確保接口在多次請(qǐng)求時(shí)只執(zhí)行一次,避免重復(fù)處理和數(shù)據(jù)不一致,每種方法都有其適用場(chǎng)景和優(yōu)勢(shì),通過(guò)實(shí)際測(cè)試驗(yàn)證了冪等性邏輯的有效性
    2025-01-01
  • mybatis?plus自動(dòng)生成代碼的示例代碼

    mybatis?plus自動(dòng)生成代碼的示例代碼

    本文主要介紹了mybatis?plus自動(dòng)生成代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 解析Java中未被捕獲的異常以及try語(yǔ)句的嵌套使用

    解析Java中未被捕獲的異常以及try語(yǔ)句的嵌套使用

    這篇文章主要介紹了Java中未被捕獲的異常以及try語(yǔ)句的嵌套使用,是Java入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-09-09
  • java實(shí)現(xiàn)簡(jiǎn)單計(jì)算器功能

    java實(shí)現(xiàn)簡(jiǎn)單計(jì)算器功能

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)單計(jì)算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • MyBatis學(xué)習(xí)教程(二)—如何使用MyBatis對(duì)users表執(zhí)行CRUD操作

    MyBatis學(xué)習(xí)教程(二)—如何使用MyBatis對(duì)users表執(zhí)行CRUD操作

    這篇文章主要介紹了MyBatis學(xué)習(xí)教程(二)—如何使用MyBatis對(duì)users表執(zhí)行CRUD操作的相關(guān)資料,需要的朋友可以參考下
    2016-05-05
  • java?Collection集合接口的介紹和使用詳解

    java?Collection集合接口的介紹和使用詳解

    這篇文章主要為大家介紹了java?Collection集合接口的介紹和使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • 深入了解java NIO之Selector(選擇器)

    深入了解java NIO之Selector(選擇器)

    這篇文章主要介紹了java NIO之Selector(選擇器)的相關(guān)資料,文中講解非常詳細(xì),實(shí)例代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • 深入理解hibernate的三種狀態(tài)

    深入理解hibernate的三種狀態(tài)

    本篇文章主要介紹了深入理解hibernate的三種狀態(tài) ,主要包括了transient(瞬時(shí)狀態(tài)),persistent(持久化狀態(tài))以及detached(離線狀態(tài)),有興趣的同學(xué)可以了解一下
    2017-05-05

最新評(píng)論

修水县| 顺平县| 新昌县| 衡水市| 伊宁县| 闽侯县| 和政县| 玛纳斯县| 玉林市| 武穴市| 益阳市| 张北县| 定南县| 江北区| 龙海市| 黔江区| 宜都市| SHOW| 舞阳县| 西盟| 紫金县| 聂荣县| 阿克苏市| 宁海县| 文成县| 台北市| 安龙县| 红河县| 元谋县| 固安县| 镇康县| 南平市| 苍溪县| 汤原县| 西丰县| 禄劝| 永康市| 从化市| 报价| 嘉荫县| 广元市|