詳解Java8新特性如何防止空指針異常
Java8 新特性如何防止空指針異常
要說(shuō) Java 編程中哪個(gè)異常是你印象最深刻的,那 NullPointerException
空指針可以說(shuō)是臭名昭著的。不要說(shuō)初級(jí)程序員會(huì)碰到, 即使是中級(jí),專家級(jí)程序員稍不留神,就會(huì)掉入這個(gè)坑里。
Null
引用的發(fā)明者 Tony Hoare 曾在 2009 年作出道歉聲明,聲明中表示,到目前為止,空指針異常大約給企業(yè)已造成數(shù)十億美元的損失。
下面是 Tony Hoare 的原話:
我將 Null 引用的設(shè)計(jì)稱為是一個(gè)數(shù)十億美元的錯(cuò)誤。1965 那年,我正在用面向?qū)ο笳Z(yǔ)言(ALGOL W) 設(shè)計(jì)首個(gè)功能全面的系統(tǒng)。當(dāng)時(shí)我的考量是,確保所有被使用的引用都是安全的,編譯器會(huì)自動(dòng)進(jìn)行檢查。但是,我沒(méi)有抵住誘惑,加入了 Null 引用,僅僅是為了實(shí)現(xiàn)起來(lái)省事。這之后,它導(dǎo)致了數(shù)不清的 bug、錯(cuò)誤和系統(tǒng)崩潰,也為企業(yè)導(dǎo)致了不可估量的損失。
事已至此,我們必須學(xué)會(huì)面對(duì)它。So, 我們要如何防止空指針異常呢?
唯一的辦法就是對(duì)可能為 Null 的對(duì)象添加檢查。但是 Null 檢查是繁瑣且痛苦的。所以一些比較新的語(yǔ)言為了處理 Null 檢查,特意添加了特殊的語(yǔ)法,如空合并運(yùn)算符。
在 Groovy 或 Kotlin 這樣的語(yǔ)言中也被稱為
Elvis
運(yùn)算符。
不幸的是,在老版本的 Java 中并沒(méi)有提供這樣的語(yǔ)法糖。Java8 中在這方面做了改進(jìn)。所以,這篇文章就特意來(lái)介紹一下如何在 Java8 中利用新特性來(lái)編寫防止 NullPointerException
的發(fā)生。
Java8 中如何加強(qiáng)對(duì) Null 對(duì)象的檢查?
接下來(lái),我們細(xì)說(shuō)一下如何通過(guò) Optional
類來(lái)對(duì)對(duì)象做空校驗(yàn):
在業(yè)務(wù)系統(tǒng)中,對(duì)象中嵌套對(duì)象是經(jīng)常發(fā)生的場(chǎng)景,如下示例代碼:
?// 最外層對(duì)象 ?class Outer { ? ? ?Nested nested; ? ? ?Nested getNested() { ? ? ? ? ?return nested; ? ? } ?} ?// 第二層對(duì)象 ?class Nested { ? ? ?Inner inner; ? ? ?Inner getInner() { ? ? ? ? ?return inner; ? ? } ?} ?// 最底層對(duì)象 ?class Inner { ? ? ?String foo; ? ? ?String getFoo() { ? ? ? ? ?return foo; ? ? } ?}
業(yè)務(wù)中,假設(shè)我們需要獲取 Outer
對(duì)象對(duì)底層的 Inner
中的 foo
屬性,我們必須寫一堆的非空校驗(yàn),來(lái)防止發(fā)生 NullPointerException
:
?// 繁瑣的代碼 ?Outer outer = new Outer(); ?if (outer != null && outer.nested != null && outer.nested.inner != null) { ? ? ?System.out.println(outer.nested.inner.foo); ?}
通過(guò) Optional
在 Java8 中,我們有更優(yōu)雅的解決方式,那就是使用 Optional
是說(shuō),我們可以在一行代碼中,進(jìn)行流水式的 map
操作。而 map 方法內(nèi)部會(huì)自動(dòng)進(jìn)行空校驗(yàn):
?Optional.of(new Outer()) ? ? .map(Outer::getNested) ? ? .map(Nested::getInner) ? ? .map(Inner::getFoo ? ? .ifPresent(System.out::println); // 如果不為空,最終輸出 foo 的值
通過(guò) suppiler 函數(shù)自定義增強(qiáng) API
上面這種方式個(gè)人感覺(jué)還是有點(diǎn)啰嗦,我們可以利用 suppiler
函數(shù)來(lái)出一個(gè)終極解決方案:
?public static <T> Optional<T> resolve(Supplier<T> resolver) { ? ? ?try { ? ? ? ? ?T result = resolver.get(); ? ? ? ? ?return Optional.ofNullable(result); ? ? } ? ? ?catch (NullPointerException e) { ? ? ? ? ?// 可能會(huì)拋出空指針異常,直接返回一個(gè)空的 Optional 對(duì)象 ? ? ? ? ?return Optional.empty(); ? ? } ?}
利用上面的 resolve
方法來(lái)重構(gòu)上述的非空校驗(yàn)代碼段:
?Outer obj = new Outer(); ?// 直接調(diào)用 resolve 方法,內(nèi)部做空指針的處理 ?resolve(() -> obj.getNested().getInner().getFoo()); ? ? .ifPresent(System.out::println); // 如果不為空,最終輸出 foo 的值
最后
你需要知道的是,上面這兩個(gè)解決方案并沒(méi)傳統(tǒng)的 null
檢查性能那么高效。但在絕大部分業(yè)務(wù)場(chǎng)景下,舍棄那么一丟丟的性能來(lái)方便編碼,是完全可取, 除非是那種對(duì)性能有嚴(yán)格要求的場(chǎng)景,我們才不建議使用。
到此這篇關(guān)于詳解Java8新特性如何防止空指針異常的文章就介紹到這了,更多相關(guān)Java8空指針異常內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java使用Curator進(jìn)行ZooKeeper操作的詳細(xì)教程
Apache Curator 是一個(gè)基于 ZooKeeper 的 Java 客戶端庫(kù),它極大地簡(jiǎn)化了使用 ZooKeeper 的開(kāi)發(fā)工作,在分布式系統(tǒng)中,ZooKeeper 通常被用來(lái)作為協(xié)調(diào)服務(wù),而 Curator 則為我們提供了更簡(jiǎn)潔易用的接口,本文將介紹 Curator 的核心功能及實(shí)踐樣例,需要的朋友可以參考下2025-04-04SpringBoot使用log4j2將日志記錄到文件及自定義數(shù)據(jù)庫(kù)的配置方法
這篇文章主要介紹了SpringBoot使用log4j2將日志記錄到文件及自定義數(shù)據(jù)庫(kù)的配置方法,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-03-03java實(shí)現(xiàn)斐波那契數(shù)列的3種方法
這篇文章主要介紹了java實(shí)現(xiàn)斐波那契數(shù)列的3種方法,有需要的朋友可以參考一下2014-01-01Springboot實(shí)現(xiàn)MQTT通信的示例代碼
本文主要介紹了Springboot實(shí)現(xiàn)MQTT通信的示例代碼,包含了MQTT協(xié)議的特點(diǎn)和工作原理等,具有一定的參考價(jià)值,感興趣的可以了解一下2025-01-01Windows下使用IDEA搭建Hadoop開(kāi)發(fā)環(huán)境的詳細(xì)方法
這篇文章主要介紹了Windows下使用IDEA搭建Hadoop開(kāi)發(fā)環(huán)境,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12