一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - Java8中Optional類的使用說(shuō)明

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

2022-03-10 00:49永動(dòng)的圖靈機(jī) Java教程

Optional類主要解決的問題是臭名昭著的空指針異常(NullPointerException),每個(gè)Java程序員都非常了解的異常,這篇文章主要給大家介紹了關(guān)于Java8中Optional類使用的相關(guān)資料,需要的朋友可以參考下

簡(jiǎn)介

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

歷史

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

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

  • 錯(cuò)誤之源。

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

  • 代碼膨脹。

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

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

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

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

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

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

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

方案

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

場(chǎng)景引入

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * >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ú)";
}

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

方法說(shuō)明

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

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

  • Optional(T var1)

源碼

?
1
2
3
4
5
6
7
8
9
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)造器支持一個(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()源碼

?
1
2
3
4
5
6
7
8
9
10
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ù)了一個(gè)null值的對(duì)象,使用empty靜態(tài)方法即可返回該空值對(duì)象

of(T var0)源碼

?
1
2
3
public static <T> Optional<T> of(T var0) {
    return new Optional(var0);
}

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

ofNullable(T var0)源碼

?
1
2
3
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,不過使用Optional.empty()就完全沒事兒,它是Op-tional類的一個(gè)有效對(duì)象,多種場(chǎng)景都能調(diào)用,非常有用。

舉例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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)

源碼

?
1
2
3
4
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)

源碼

?
1
2
3
4
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類型

舉例

?
1
2
3
4
5
6
7
8
9
10
11
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)?/code>
    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對(duì)象1

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

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

源碼

orElse源碼

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

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

orElseGet源碼

?
1
2
3
4
5
6
7
8
9
10
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è)方法類似,當(dāng)optional中的包裹值不為空時(shí)返回包裹的值,若為空?qǐng)?zhí)行orElseGet中的Supplier方法

orElseThrow源碼

?
1
2
3
4
5
6
7
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中的包裹值不為空時(shí)返回包裹的值,若為空拋出orElseThrow中的Supplier.get的異常方法

舉例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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)

源碼

?
1
2
3
4
isPresent()源碼
public boolean isPresent() {
    return this.value != null;
}

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

ifPresent(Consumer var1)源碼

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

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

舉例

?
1
2
3
4
5
6
7
8
9
10
11
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)

源碼

?
1
2
3
4
5
6
7
8
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ì)象的過濾,當(dāng)optional包裹的值不為空時(shí)返回該值,否則執(zhí)行filter入?yún)⒌腜redicate.test方法

舉例

?
1
2
3
4
5
6
7
8
9
10
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類的說(shuō)明大致已經(jīng)講完,再回到開始的時(shí)候,提到的場(chǎng)景引入,結(jié)合optional進(jìn)行改造

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
 * 實(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ǔ)充代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public static void main(String[] args) {
    //逐個(gè)放開
    // 引入
//        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類使用的文章就介紹到這了,更多相關(guān)Java8 Optional類使用內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!

原文鏈接:https://juejin.cn/post/7025925484462473246

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日本高免费观看在线播放 | 成人夜视频寂寞在线观看 | 7788av| 日本人添下面的全过程 | 亚洲欧美日韩中文字幕网址 | 精品久久免费视频 | 日本暖暖在线视频 | 国产欧美一区二区成人影院 | 久久亚洲电影www电影网 | 香蕉国产成版人视频在线观看 | 小寡妇水真多好紧 | 欧美一级视频在线高清观看 | 亚洲天堂视频在线免费观看 | 男插女的下面免费视频夜色 | 男人的天堂久久精品激情 | 欧美在线视频一区在线观看 | 成人免费视屏 | 5x社区发源地最新地址 | 欧产日产国产精品专区 | 国产欧美亚洲精品第一页青草 | 国产成人精品视频午夜 | 国产成人一区二区三区影院免费 | 美国美女hd18| 日本嫩小xxxxhd | 国产一卡二卡3卡4卡四卡在线视频 | 操比图片 | 男人的天堂久久精品激情 | 精品国产综合 | 好男人好资源在线观看免费 | jux539原千岁在线播放 | 国内精品露脸在线视频播放 | 国产成人h综合亚洲欧美在线 | 欧美成人二区 | 久久99re2热在线播放7 | 无码专区aaaaaa免费视频 | 欧美干b视频 | 亚洲青草 | 99 久久99久久精品免观看 | 精精国产xxxx视频在线播放器 | 日韩亚洲一区中文字幕在线 | www.男人天堂 |