日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > windows >内容正文

windows

null 不好,我真的推荐你使用 Optional

發(fā)布時(shí)間:2023/11/20 windows 49 coder
生活随笔 收集整理的這篇文章主要介紹了 null 不好,我真的推荐你使用 Optional 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

"Null 很糟糕." - Doug Lea。

Doug Lea 是一位美國(guó)的計(jì)算機(jī)科學(xué)家,他是 Java 平臺(tái)的并發(fā)和集合框架的主要設(shè)計(jì)者之一。他在 2014 年的一篇文章中說(shuō)過(guò):“Null sucks.”1,意思是 null 很糟糕。他認(rèn)為 null 是一種不明確的表示,它既可以表示一個(gè)值不存在,也可以表示一個(gè)值未知,也可以表示一個(gè)值無(wú)效。這樣就會(huì)導(dǎo)致很多邏輯錯(cuò)誤和空指針異常,給程序員帶來(lái)很多麻煩。他建議使用 Optional 類來(lái)封裝可能為空的值,從而提高代碼的可讀性和健壯性。

"發(fā)明 null 引用是我的十億美元錯(cuò)誤。" - Sir C. A. R. Hoare。

Sir C. A. R. Hoare 是一位英國(guó)的計(jì)算機(jī)科學(xué)家,他是快速排序算法、Hoare 邏輯和通信順序進(jìn)程等重要概念的發(fā)明者。他在 2009 年的一個(gè)軟件會(huì)議上道歉說(shuō):“I call it my billion-dollar mistake. It was the invention of the null reference in 1965.”,意思是他把 null 引用稱為他的十億美元錯(cuò)誤。他說(shuō)他在 1965 年設(shè)計(jì) ALGOL W 語(yǔ)言時(shí),引入了 null 引用的概念,用來(lái)表示一個(gè)對(duì)象變量沒(méi)有指向任何對(duì)象。他當(dāng)時(shí)認(rèn)為這是一個(gè)很簡(jiǎn)單和自然的想法,但后來(lái)發(fā)現(xiàn)這是一個(gè)非常糟糕的設(shè)計(jì),因?yàn)樗鼘?dǎo)致了無(wú)數(shù)的錯(cuò)誤、漏洞和系統(tǒng)崩潰。他說(shuō)他應(yīng)該使用一個(gè)特殊的對(duì)象來(lái)表示空值,而不是使用 null。

自作者從事 Java 編程一來(lái),就與 null 引用相伴,與 NullPointerException 相遇已經(jīng)是家常便飯了。

null 引用是一種表示一個(gè)對(duì)象變量沒(méi)有指向任何對(duì)象的方式,它是 Java 語(yǔ)言中的一個(gè)特殊值,也是導(dǎo)致空指針異常(NullPointerException)的主要原因。雖然 null 引用可以用來(lái)表示一個(gè)值不存在或未知,也可以用來(lái)節(jié)省內(nèi)存空間。但是它也不符合面向?qū)ο蟮乃枷耄驗(yàn)樗皇且粋€(gè)對(duì)象,不能調(diào)用任何方法或?qū)傩浴?/p>

可以看到,null 引用并不好,我們應(yīng)該盡量避免使用 null,那么我們?cè)撛趺幢苊?null 引用引起的邏輯錯(cuò)誤和運(yùn)行時(shí)異常嘞?

其實(shí)這個(gè)問(wèn)題 Java 的設(shè)計(jì)者也知道,于是他們?cè)?Java8 之后設(shè)計(jì)引入了 Optional 類解決這個(gè)問(wèn)題,本文將給大家詳細(xì)介紹下 Optional 類的設(shè)計(jì)目的以及使用方法。

Optional 類是什么?

Optional 類是 java 8 中引入的一個(gè)新的類,它的作用是封裝一個(gè)可能為空的值,從而避免空指針異常(NullPointerException)。Optional 類可以看作是一個(gè)容器,它可以包含一個(gè)非空的值,也可以為空。Optional 類提供了一些方法,讓我們可以更方便地處理可能為空的值,而不需要顯式地進(jìn)行空值檢查或者使用 null。

推薦作者開(kāi)源的 H5 商城項(xiàng)目waynboot-mall,這是一套全部開(kāi)源的微商城項(xiàng)目,包含三個(gè)項(xiàng)目:運(yùn)營(yíng)后臺(tái)、H5 商城前臺(tái)和服務(wù)端接口。實(shí)現(xiàn)了商城所需的首頁(yè)展示、商品分類、商品詳情、商品 sku、分詞搜索、購(gòu)物車、結(jié)算下單、支付寶/微信支付、收單評(píng)論以及完善的后臺(tái)管理等一系列功能。 技術(shù)上基于最新得 Springboot3.0、jdk17,整合了 MySql、Redis、RabbitMQ、ElasticSearch 等常用中間件。分模塊設(shè)計(jì)、簡(jiǎn)潔易維護(hù),歡迎大家點(diǎn)個(gè) star、關(guān)注我。

github 地址:https://github.com/wayn111/waynboot-mall

Optional 類的設(shè)計(jì)

Optional 類的設(shè)計(jì)是基于函數(shù)式編程的思想,它借鑒了 Scala 和 Haskell 等語(yǔ)言中的 Option 類型。Optional 類實(shí)現(xiàn)了 java.util.function 包中的 Supplier、Consumer、Predicate、Function 等接口,這使得它可以和 lambda 表達(dá)式或者方法引用一起使用,形成更簡(jiǎn)潔和優(yōu)雅的代碼。

Optional 類被 final 修飾,因此它是一個(gè)不可變的類,它有兩個(gè)靜態(tài)方法用于創(chuàng)建 Optional 對(duì)象。

Optional.empty()

Optional.empty 表示一個(gè)空的 Optional 對(duì)象,它不包含任何值。

// 創(chuàng)建一個(gè)空的 Optional 對(duì)象
Optional<String> empty = Optional.empty();

Optional.of(T value)

Optional.of 表示一個(gè)非空的 Optional 對(duì)象,它包含一個(gè)非空的值。

// 創(chuàng)建一個(gè)非空的 Optional 對(duì)象
Optional<String> hello = Optional.of("Hello");

Optional.ofNullable(T value)

注意,如果我們使用 Optional.of 方法傳入一個(gè) null 值,會(huì)拋出 NullPointerException。如果我們不確定一個(gè)值是否為空,可以使用 Optional.ofNullable 方法,它會(huì)根據(jù)值是否為空,返回一個(gè)相應(yīng)的 Optional 對(duì)象。例如:

// 創(chuàng)建一個(gè)可能為空的 Optional 對(duì)象
Optional<String> name = Optional.ofNullable("Hello");

Optional 對(duì)象的使用方法

Optional 對(duì)象提供了一些方法,讓我們可以更方便地處理可能為空的值,而不需要顯式地進(jìn)行空值檢查或者使用 null。以下是一些常用的方法。

isPresent()

判斷 Optional 對(duì)象是否包含一個(gè)非空的值,返回一個(gè)布爾值。

get()

如果 Optional 對(duì)象包含一個(gè)非空的值,返回該值,否則拋出 NoSuchElementException 異常。


// 使用 isPresent 和 get 方法
Optional<String> name = Optional.ofNullable("tom");
if (name.isPresent()) {
    System.out.println("Hello, " + name.get());
} else {
    System.out.println("Name is not available");
}
// 輸出:Hello tom

ifPresent(Consumer<? super T> action)

如果 Optional 對(duì)象包含一個(gè)非空的值,執(zhí)行給定的消費(fèi)者操作,否則什么也不做。

// 使用 ifPresent(Consumer<? super T> action)
Optional<String> name = Optional.ofNullable("tom");
name.ifPresent(s -> {
    System.out.println("Hello, " + name.get());
});
// 輸出:Hello tom

orElse(T other)

如果 Optional 對(duì)象包含一個(gè)非空的值,返回該值,否則返回給定的默認(rèn)值。

// 使用 orElse(T other)
Optional<String> name = Optional.ofNullable(null);
String greeting = "Hello, " + name.orElse("Guest");
System.out.println(greeting);
// 輸出:Hello Guest

orElseGet(Supplier<? extends T> supplier)

如果 Optional 對(duì)象包含一個(gè)非空的值,返回該值,否則返回由給定的供應(yīng)者操作生成的值。

// 使用 orElseGet(Supplier<? extends T> supplier)
Optional<String> name = Optional.ofNullable(null);
String greeting = "Hello, " + name.orElseGet(() -> "Guset");
System.out.println(greeting);
// 輸出:Hello Guset

orElseThrow(Supplier<? extends X> exceptionSupplier)

如果 Optional 對(duì)象包含一個(gè)非空的值,返回該值,否則拋出由給定的異常供應(yīng)者操作生成的異常。

// 使用 orElseThrow(Supplier<? extends X> exceptionSupplier)
Optional<String> name = Optional.ofNullable(null);
String greeting = "Hello, " + name.orElseThrow(() -> new NullPointerException("null"));
// 拋出 java.lang.NullPointerException: null 異常

map(Function<? super T,? extends U> mapper)

如果 Optional 對(duì)象包含一個(gè)非空的值,對(duì)該值應(yīng)用給定的映射函數(shù),返回一個(gè)包含映射結(jié)果的 Optional 對(duì)象,否則返回一個(gè)空的 Optional 對(duì)象。

// 使用 map(Function<? super T,? extends U> mapper)
Optional<String> name = Optional.ofNullable("tom");
String greeting = "Hello, " + name.map(s -> s.toUpperCase()).get();
System.out.println(greeting);
// 輸出:Hello TOM

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

如果 Optional 對(duì)象包含一個(gè)非空的值,對(duì)該值進(jìn)行 mapper 參數(shù)操作,返回新的 Optional 對(duì)象,否則返回一個(gè)空的 Optional 對(duì)象。

// 使用 flatMap(Function<? super T,Optional<U>> mapper)
Optional<String> name = Optional.ofNullable("tom");
String greeting = name.flatMap(s -> Optional.of("Hello " + s)).get();
System.out.println(greeting);
// 輸出:Hello tom

filter(Predicate<? super T> predicate)

如果 Optional 對(duì)象包含一個(gè)非空的值,并且該值滿足給定的謂詞條件,返回包含該值的 Optional 對(duì)象,否則返回一個(gè)空的 Optional 對(duì)象。

// filter(Predicate<? super T> predicate)
Optional<String> name = Optional.ofNullable("tom");
String greeting = "Hello " + name.filter(s -> !s.isEmpty()).get();
System.out.println(greeting);
// 輸出:Hello tom

Java 9 中 Optional 改進(jìn)

Java 9 中 Optional 類有了一些改進(jìn),主要是增加了三個(gè)新的方法,分別是 stream()、ifPresentOrElse() 和 or()。這些方法可以讓我們更方便地處理可能為空的值,以及和流或其他返回 Optional 的方法結(jié)合使用。我來(lái)詳細(xì)講解一下這些方法的作用和用法。

stream()

這個(gè)方法可以將一個(gè) Optional 對(duì)象轉(zhuǎn)換為一個(gè) Stream 對(duì)象,如果 Optional 對(duì)象包含一個(gè)非空的值,那么返回的 Stream 對(duì)象就包含這個(gè)值,否則返回一個(gè)空的 Stream 對(duì)象。這樣我們就可以利用 Stream 的各種操作來(lái)處理 Optional 的值,而不需要顯式地判斷是否為空。我們可以用 stream() 方法來(lái)過(guò)濾一個(gè)包含 Optional 的列表,只保留非空的值,如下所示:

List<Optional<String>> list = Arrays.asList(
        Optional.empty(),
        Optional.of("A"),
        Optional.empty(),
        Optional.of("B")
);

// 使用 stream() 方法過(guò)濾列表,只保留非空的值
List<String> filteredList = list.stream()
        .flatMap(Optional::stream)
        .collect(Collectors.toList());

System.out.println(filteredList);
// 輸出 [A, B]

ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)

這個(gè)方法可以讓我們?cè)?Optional 對(duì)象包含值或者為空時(shí),執(zhí)行不同的操作。它接受兩個(gè)參數(shù),一個(gè)是 Consumer 類型的 action,一個(gè)是 Runnable 類型的 emptyAction。如果 Optional 對(duì)象包含一個(gè)非空的值,那么就執(zhí)行 action.accept(value),如果 Optional 對(duì)象為空,那么就執(zhí)行 emptyAction.run()。這樣我們就可以避免使用 if-else 語(yǔ)句來(lái)判斷 Optional 是否為空,而是使用函數(shù)式編程的方式來(lái)處理不同的情況。我們可以用 ifPresentOrElse() 方法來(lái)打印 Optional 的值,或者提示不可用,如下所示 :

Optional<Integer> optional = Optional.of(1);
optional.ifPresentOrElse(
    x -> System.out.println("Value: " + x),
    () -> System.out.println("Not Present.")
);

optional = Optional.empty();
optional.ifPresentOrElse(
    x -> System.out.println("Value: " + x),
    () -> System.out.println("Not Present.")
);

// 輸出:Value: 1
// 輸出:Not Present.

or(Supplier<? extends Optional<? extends T>> supplier)

這個(gè)方法可以讓我們?cè)?Optional 對(duì)象為空時(shí),返回一個(gè)預(yù)設(shè)的值。它接受一個(gè) Supplier 類型的 supplier,如果 Optional 對(duì)象包含一個(gè)非空的值,那么就返回這個(gè) Optional 對(duì)象本身,如果 Optional 對(duì)象為空,那么就返回 supplier.get() 返回的 Optional 對(duì)象。這樣我們就可以避免使用三元運(yùn)算符或者其他方式來(lái)設(shè)置默認(rèn)值,而是使用函數(shù)式編程的方式來(lái)提供備選值。我們可以用 or() 方法來(lái)設(shè)置 Optional 的默認(rèn)值,如下所示:

Optional<String> optional = Optional.of("Hello ");
Supplier<Optional<String>> supplier = () -> Optional.of("tom");
optional = optional.or(supplier);
optional.ifPresent(x -> System.out.println(x));

optional = Optional.empty();
optional = optional.or(supplier);
optional.ifPresent(x -> System.out.println(x));

// 輸出:Hello 
// 輸出:tom

為什么我推薦你使用 Optional 類

最后我總結(jié)一下使用 Optional 類的幾個(gè)好處:

  1. 可以避免空指針異常,提高代碼的健壯性和可讀性。
  2. 可以減少顯式的空值檢查和 null 的使用,使代碼更簡(jiǎn)潔和優(yōu)雅。
  3. 可以利用函數(shù)式編程的特性,實(shí)現(xiàn)更靈活和高效的邏輯處理。
  4. 可以提高代碼的可測(cè)試性,方便進(jìn)行單元測(cè)試和集成測(cè)試。

總之,Optional 類是一個(gè)非常有用的類,它可以幫助我們更好地處理可能為空的值,提高代碼的質(zhì)量和效率。所以我強(qiáng)烈推薦你在 Java 開(kāi)發(fā)中使用 Optional 類,你會(huì)發(fā)現(xiàn)它的魅力和好處。

關(guān)注公眾號(hào)【waynblog】每周分享技術(shù)干貨、開(kāi)源項(xiàng)目、實(shí)戰(zhàn)經(jīng)驗(yàn)、國(guó)外優(yōu)質(zhì)文章翻譯等,您的關(guān)注將是我的更新動(dòng)力!

總結(jié)

以上是生活随笔為你收集整理的null 不好,我真的推荐你使用 Optional的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。