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

Java8中Optional類的使用說明

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

簡介

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

歷史

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

null帶來的種種問題

  • 錯誤之源。

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

  • 代碼膨脹。

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

  • 自身是毫無意義的。

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

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

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

  • 在Java的類型系統(tǒng)上開了個口子。

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

方案

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

場景引入

首先我們引入一個常見的兩個場景

/**
 * >1 引入,常規(guī)判斷一個學(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 "無";
}

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

方法說明

構(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)建,只能通過類中的其他靜態(tài)方法創(chuàng)建,optional構(gòu)造器支持一個泛型入?yún)ⅲ腋膮?shù)不能為空

創(chuàng)建Optional對象

  • 聲明一個空的Optional: Optional<T> empty()
  • 依據(jù)一個非空值創(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類中維護(hù)了一個null值的對象,使用empty靜態(tài)方法即可返回該空值對象

of(T var0)源碼

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

返回常見的有參構(gòu)造對象,注意由于構(gòu)造器要求入?yún)⒉荒転榭眨虼薿f方法的入?yún)榭盏脑?,依然會報NPE異常

ofNullable(T var0)源碼

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

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

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

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

舉例

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

    // 2. of構(gòu)建非空和空對象(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)建非空和空對象(Optional.empty)
    /*Optional<String> o3 = Optional.ofNullable("test");
    System.out.println(o3);
    Optional<Object> o4 = Optional.ofNullable(null);
    System.out.println(o4);*/
}

使用map從Optional對象中提取和轉(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包裹的值為空時直接放回空對象,否則執(zhí)行入?yún)⒅械腇unction.apply方法

使用flatMap鏈接Optional對象

  • 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方法中,返回類型為optional類型

舉例

public static void testOptionalMap() {
    Student student1 = getDefaultStudent();
    Student student2 = getBackStudent();
    // map
    String school1 = Optional.ofNullable(student1).map(i -> i.getName()).orElse("無名");
    String school2 = Optional.ofNullable(student2).map(i -> i.getName()).orElse("無名");
    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("沒上大學(xué)");
    System.out.println("school3: " + school3);
}

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

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

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

源碼

orElse源碼

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

當(dāng)optional中的包裹值不為空時返回包裹的值,若為空則返回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;
    }
}

與上個方法類似,當(dāng)optional中的包裹值不為空時返回包裹的值,若為空執(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();
    }
}

類似的,當(dāng)optional中的包裹值不為空時返回包裹的值,若為空拋出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對象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包裹的值不為空時,繼續(xù)處理入?yún)⒅蠧onsumer.accept的方法。類似于 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();
    }
}

用于對optional對象的過濾,當(dāng)optional包裹的值不為空時返回該值,否則執(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);
}

實戰(zhàn)

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

/**
 * 實戰(zhàn)1
 * 針對原來的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ù)異常"));
}

/**
 * 實戰(zhàn)1
 * 針對原來的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());
}


附:

補充代碼

public static void main(String[] args) {
    //逐個放開
    // 引入
//        System.out.println(checkIsPublicV1(stu2));
//        System.out.println(getAdultV1(stu2));
    // optional方法
//        testOptionalBuild();
//        testOptionalOrElse();
//        testOptionalIfPresent();
//        testOptionalMap();
//        testOptionalFilter();
    // 實戰(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實戰(zhàn)

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

總結(jié)

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

相關(guān)文章

  • SpringBoot實現(xiàn)熱部署的三種方式

    SpringBoot實現(xiàn)熱部署的三種方式

    本文主要介紹了SpringBoot實現(xiàn)熱部署的三種方式,主要包括配置pom.xml文件,使用插件的執(zhí)行命令mvn spring-boot:run啟動項,使用springloader本地啟動修改jvm參數(shù),使用devtools工具包,感興趣的可以了解一下
    2023-12-12
  • 圖解Java經(jīng)典算法插入排序的原理與實現(xiàn)

    圖解Java經(jīng)典算法插入排序的原理與實現(xiàn)

    插入排序的算法描述是一種簡單直觀的排序算法。其原理是通過構(gòu)建有序序列,對于未排序數(shù)據(jù),在已排序序列中從后向前掃描,找到相應(yīng)位置并插入。本文將用Java語言實現(xiàn)插入排序算法并進(jìn)行可視化,感興趣的可以了解一下
    2022-09-09
  • 微信js-sdk+JAVA實現(xiàn)“分享到朋友圈”和“發(fā)送給朋友”功能詳解

    微信js-sdk+JAVA實現(xiàn)“分享到朋友圈”和“發(fā)送給朋友”功能詳解

    本文分享了微信js-sdk+JAVA實現(xiàn)“分享到朋友圈”和“發(fā)送給朋友”功能介紹,大家可以參考一下
    2018-03-03
  • Java將字符串String轉(zhuǎn)換為整型Int的兩種方式

    Java將字符串String轉(zhuǎn)換為整型Int的兩種方式

    這篇文章主要介紹了Java如何將字符串String轉(zhuǎn)換為整型Int,在 Java 中要將 String 類型轉(zhuǎn)化為 int 類型時,需要使用 Integer 類中的 parseInt() 方法或者 valueOf() 方法進(jìn)行轉(zhuǎn)換,本文通過實例代碼給大家詳細(xì)講解,需要的朋友可以參考下
    2023-04-04
  • JAVA使用POI(XSSFWORKBOOK)讀取EXCEL文件過程解析

    JAVA使用POI(XSSFWORKBOOK)讀取EXCEL文件過程解析

    這篇文章主要介紹了JAVA使用POI(XSSFWORKBOOK)讀取EXCEL文件過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-08-08
  • springboot項目啟動自動跳轉(zhuǎn)到瀏覽器的操作代碼

    springboot項目啟動自動跳轉(zhuǎn)到瀏覽器的操作代碼

    這篇文章主要介紹了springboot項目啟動自動跳轉(zhuǎn)到瀏覽器的操作代碼,本文圖文實例代碼相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2024-03-03
  • 一文詳解Spring?AOP的配置與使用

    一文詳解Spring?AOP的配置與使用

    面向切面編程(俗稱AOP)提供了一種面向?qū)ο缶幊?俗稱OOP)的補充,面向?qū)ο缶幊套詈诵牡膯卧穷?class),然而面向切面編程最核心的單元是切面(Aspects)。本文就來和大家聊聊AOP的配置與使用,感興趣的可以了解一下
    2022-11-11
  • Springboot實現(xiàn)ModbusTCP通信的示例詳解

    Springboot實現(xiàn)ModbusTCP通信的示例詳解

    ModbusTCP協(xié)議是Modbus由MODICON公司于1979年開發(fā),是一種工業(yè)現(xiàn)場總線協(xié)議標(biāo)準(zhǔn),本文主要介紹了Springboot實現(xiàn)ModbusTCP通信的相關(guān)知識,需要的可以參考下
    2023-12-12
  • Java基礎(chǔ)教程之HashMap迭代刪除使用方法

    Java基礎(chǔ)教程之HashMap迭代刪除使用方法

    這篇文章主要給大家介紹了關(guān)于Java基礎(chǔ)教程之HashMap迭代刪除使用方法的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05
  • Java流程控制語句最全匯總(上篇)

    Java流程控制語句最全匯總(上篇)

    這篇文章主要介紹了Java流程控制語句最全匯總(上篇),本文章內(nèi)容詳細(xì),通過案例可以更好的理解數(shù)組的相關(guān)知識,本模塊分為了三部分,本次為上篇,需要的朋友可以參考下
    2023-01-01

最新評論