偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

細(xì)說(shuō)Java中的空指針異常

譯文
開(kāi)發(fā) 前端
本文將和您討論空指針異常(Null Pointer Exception)的常見(jiàn)原因,以及如何避免它的各種優(yōu)秀實(shí)踐。

空指針(Null Pointer Exception,NPE)是Java中最常見(jiàn)不過(guò)的異常了。其原因雖然顯而易見(jiàn),但是開(kāi)發(fā)人員往往會(huì)忽略,或未能及時(shí)采取措施。本文將和您詳細(xì)討論空指針問(wèn)題的根源,以及對(duì)應(yīng)的解決方法。

空引用破壞了Java類型安全性

Java通過(guò)提供??編譯類型的安全性??(Compile Type Safety),來(lái)保證開(kāi)發(fā)人員不會(huì)錯(cuò)配不同的變量類型。在下面的示例中,我們?cè)噲D將整形(Integer)值分配給某個(gè)字符串(String)變量,而Java會(huì)及時(shí)提醒您。

Java雖然會(huì)在編譯過(guò)程中,去驗(yàn)證變量和賦值的類型,但是由于空值(NULL)代表了所有未初始化的對(duì)象,因此空值可以被分配為任何類型(如下圖所示),且Java不會(huì)報(bào)錯(cuò)。

例如,Java允許如下賦值情況的出現(xiàn):

這些對(duì)象在未被初始化的情況下,就指向了空引用,往往會(huì)產(chǎn)生Java類型的安全性漏洞。如下代碼段所示,就Java而言,Null和真實(shí)對(duì)象可能并沒(méi)有什么區(qū)別,但是它會(huì)導(dǎo)致一些不可實(shí)現(xiàn)的操作:

同時(shí),由于Null屬于String類型,因此在編譯如下代碼段時(shí),Java甚至都不會(huì)有任何警告。

但是,我們一旦運(yùn)行該程序代碼,就會(huì)出現(xiàn)失敗,并且會(huì)被提示如下的空指針異常:

空指針異常的定義

空指針異常屬于運(yùn)行時(shí)的異常。當(dāng)Java嘗試去調(diào)用真實(shí)對(duì)象上的任何方法時(shí),如果在運(yùn)行時(shí)中,該對(duì)象調(diào)用的是空引用(Null Reference),那么就會(huì)拋出異常。您可以通過(guò)鏈接--https://dzone.com/articles/java-exceptions-1,找到有關(guān)異常、及其根源的更多詳細(xì)信息。

由于種種原因,開(kāi)發(fā)人員時(shí)常會(huì)忘記初始化對(duì)象和驗(yàn)證對(duì)象。這往往是導(dǎo)致空指針異常的根源。下面讓我們根據(jù)上述例子,討論如何修復(fù)NPE。

解釋空指針異常

下面是一個(gè)帶有Address字段的User對(duì)象。它們都可能為空。

使用Simple != Null Check避免空指針異常

下面是通過(guò)簡(jiǎn)單的檢查(并非Null Check),來(lái)防止該問(wèn)題的發(fā)生:

作為改進(jìn)方案,我們可以使用Optional,并通過(guò)map函數(shù),編寫(xiě)出如下類似于前例的等效語(yǔ)句:

與簡(jiǎn)單的Null Check相比,Optional能夠再次確保我們?cè)趇fPresent lambda中使用的數(shù)據(jù)不為空。這里的再次是指:如果User或Address的確為空的話,而且ifPresent被忽略了的話,即使我們忘記了使用Optional的相關(guān)功能,它也會(huì)以突出顯示.get()的方式,并提醒我們?yōu)樵O(shè)計(jì)提供Null Check。

其實(shí),早在2014年,Optional就作為可選特性,在Java 1.8中被發(fā)布了。不過(guò)由于如下原因,導(dǎo)致其至今未能被廣泛地使用:

  • 由于Java本身非常冗長(zhǎng),因此Optional也跟著變得冗長(zhǎng)起來(lái),因此容易影響到代碼的整體質(zhì)量。
  • 對(duì)于各種map/flatmap/ifpresent邏輯,開(kāi)發(fā)人員更傾向使用簡(jiǎn)單明了的Null Check。
  • Optional本身可能會(huì)導(dǎo)致開(kāi)發(fā)人員創(chuàng)建更多NPE,例如使用到Optional.of(nullable)。

因此,鑒于上述原因,一些開(kāi)發(fā)團(tuán)隊(duì)會(huì)更喜歡使用Null Check,并且會(huì)用一堆邏輯性的測(cè)試覆蓋率,來(lái)避免潛在的NPE。

Null Check和Optional真的能夠解決問(wèn)題嗎?

雖然上面討論到的Null Check與Optional的使用目的都是針對(duì)空值數(shù)據(jù)進(jìn)行驗(yàn)證。其中,Optional還可以提醒開(kāi)發(fā)者返回值為空。但是,它們無(wú)法解決隱藏在開(kāi)發(fā)者頭腦中的關(guān)鍵問(wèn)題——在編譯步驟中出現(xiàn)的疏忽與遺漏。

@NotNull@Nullable注釋處理器有助于識(shí)別潛在的空值

因此,我們需要一個(gè)解決方案,可以在編譯步驟中讀取代碼,并通知開(kāi)發(fā)人員他們可能疏漏的潛在NPE場(chǎng)景。對(duì)此,我們可以使用具有豐富功能的Java注釋處理器(Annotation Processors)。您可以通過(guò)鏈接--https://www.javacodegeeks.com/2015/09/java-annotation-processors.html,了解如何使用注釋處理器,來(lái)檢查可變性的示例。

目前,業(yè)界有幾種與NPE問(wèn)題相關(guān)的注釋處理器。它們并非遵循完全相同的方法。下面我們將重點(diǎn)討論@NotNull和@Nullable兩種注釋提供工具。

Lombok的@NotNull注釋

Lombok(譯者注:一種Java庫(kù),提供了一組非常實(shí)用的注釋)的@NotNull注釋可用于生成那些僅在運(yùn)行時(shí)(Runtime)阻斷執(zhí)行的非Null Check。下面的代碼段展示了該注釋、及其等效語(yǔ)句。

檢查器框架的@NonNull和@Nullable注釋處理器

??檢查器框架??(Checker Framework)提供了@NonNull和@Nullable注釋,以及可以識(shí)別潛在Null Check的編譯處理器的步驟。該框架可以通過(guò)強(qiáng)制開(kāi)發(fā)人員指定的Nullability,來(lái)發(fā)現(xiàn)潛在的空值。因此,您的代碼必須明確聲明可返回的結(jié)果為Nullable或NotNullable。下面讓我們來(lái)看一個(gè)可能返回Null,而非String的簡(jiǎn)單方法:

現(xiàn)在,讓我們使用檢查器框架,來(lái)檢驗(yàn)是否可以完成編譯。

如您所見(jiàn),它報(bào)出了錯(cuò)誤,并且返回了一個(gè)未使用@Nullable注釋標(biāo)記的疑似空字符串。那么,讓我們將其標(biāo)記為@Nullable試試:

如果我們?cè)俅芜\(yùn)行編譯檢查,則會(huì)得到如下錯(cuò)誤信息:

可見(jiàn),檢查器框架在第19行發(fā)現(xiàn)了一個(gè)潛在問(wèn)題,即:我們?cè)贜ullable字符串上調(diào)用了.length()。下面,讓我們使用Null Check和Optional的ifPresent來(lái)予以修復(fù):

在編譯之后,我們將得到如下成功的構(gòu)建信息:

檢查器框架的限制

至此,檢查器框架向我們展示了良好的檢查結(jié)果,并且突出了潛在的NPE。不過(guò),其代價(jià)是我們必須通過(guò)@Nullable方法,標(biāo)記所有可能為空的方法。為了突破該強(qiáng)制性的限制,我們可以創(chuàng)建一個(gè)帶有兩個(gè)字段的簡(jiǎn)單類,并且將其中一個(gè)字段標(biāo)記為@NonNull:

下面是經(jīng)由檢查器框架的檢查結(jié)果:

顯然,檢查器框架會(huì)強(qiáng)制要求我們構(gòu)造一個(gè)初始化id值的構(gòu)造函數(shù),例如:

可見(jiàn),檢查器框架不僅能夠識(shí)別潛在的NPE,而且還會(huì)迫使我們遵循特定的設(shè)計(jì)要求。這在某種程度上犧牲了框架開(kāi)發(fā)的靈活性。如果您對(duì)該問(wèn)題有興趣的話,可以通過(guò)如下命令克隆我為您準(zhǔn)備的示例:

git clone https://github.com/isicju/checker_framework_example


若要運(yùn)行檢查器框架的話,請(qǐng)使用如下命令:

Mvn clean compile


檢查器框架的替代方案:Intellij Idea @NotNull注釋

當(dāng)然,檢查器框架并非唯一的解決方案,Intellij Idea也提供了自己的注釋--@NotNull和@Nullable,并嵌入到了IDE的插件中。目前,我尚未找到在maven編譯步驟中添加它的方法。如果您對(duì)此有經(jīng)驗(yàn)的話,歡迎您追加評(píng)論。

小結(jié)

通過(guò)上述討論,我們可以看到,避免空指針異常的方法可以總結(jié)為:

  • 首選使用Optional,而不是傳遞Null
  • 使用檢查器框架

當(dāng)然,檢查器框架會(huì)給您的開(kāi)發(fā)帶來(lái)一些限制。在實(shí)踐中,如果您必須避免使用Lombok、甚至是Builder Pattern(建造者模式)的話,我建議您基于生產(chǎn)環(huán)境的穩(wěn)定性考慮,去使用檢查器框架。

譯者介紹

陳 峻 (Julian Chen),51CTO社區(qū)編輯,具有十多年的IT項(xiàng)目實(shí)施經(jīng)驗(yàn),善于對(duì)內(nèi)外部資源與風(fēng)險(xiǎn)實(shí)施管控,專注傳播網(wǎng)絡(luò)與信息安全知識(shí)與經(jīng)驗(yàn);持續(xù)以博文、專題和譯文等形式,分享前沿技術(shù)與新知;經(jīng)常以線上、線下等方式,開(kāi)展信息安全類培訓(xùn)與授課。

【原標(biāo)題】Null Pointer Exception in Java: Causes and Ways to Avoid It(作者:Dmitry Egorov)


責(zé)任編輯:華軒 來(lái)源: 51CTO
相關(guān)推薦

2015-07-30 10:12:32

JavaNullAssert

2023-10-08 11:09:22

Optional空指針

2024-02-01 12:09:17

Optional容器null

2024-02-28 09:03:20

Optional空指針Java

2021-02-28 21:47:51

Java語(yǔ)法糖算數(shù)

2021-05-12 07:03:25

Switch報(bào)空指針

2021-11-15 06:56:45

系統(tǒng)運(yùn)行空指針

2015-01-05 10:01:20

Java

2024-12-06 10:12:20

2024-08-12 08:28:35

2009-09-28 11:25:17

PersistentQKestrelScala

2022-01-04 23:13:57

語(yǔ)言PanicGolang

2020-11-02 07:43:33

前端空指針數(shù)據(jù)

2009-06-25 14:05:40

Java應(yīng)用技巧

2020-07-02 22:42:18

Java異常編程

2013-04-07 10:01:26

Java異常處理

2011-04-11 11:09:50

this指針

2015-03-16 10:33:14

Swift指針

2015-01-21 16:25:29

Swift指針

2024-10-15 15:58:11

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)