<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何避免 Java 中的“NullPointerException”

          共 3558字,需瀏覽 8分鐘

           ·

          2022-04-24 23:25


          1

          最常見的異常


          NullPointerException (NPE) 是 Java 中最常見的異常。此異常的原因是已知的,但在大多數(shù)情況下,開發(fā)人員更愿意忽略它并且不采取任何措施。我個人認(rèn)為這種行為的原因如下:?


          • 大多數(shù)開發(fā)人員在這里沒有看到任何問題,并將所有 NPE 異常都視為開發(fā)人員的錯。?

          • 意識到這個設(shè)計問題的開發(fā)人員不知道如何解決它。?


          在本文中,我將解釋這個問題的根源并提供解決該問題的方法。



          2

          問題的根源:Java 弱類型安全


          你聽說過編譯類型安全嗎?如果不在本文中,您可以了解它是什么以及編譯時和類型安全之間的區(qū)別。


          Java 提供了編譯類型安全,它向開發(fā)人員保證他不能不匹配不同的變量類型。而且,如果您這樣做了 - Java 甚至?xí)诰幾g步驟中讓他知道。在上面的示例中,我們嘗試分配給 String 變量 Integer 值:


          字符串變量



          3

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


          Java 在編譯期間驗證變量的類型和賦值的類型。那有什么問題呢?好吧,問題是 NULL 值。Null 值代表所有未初始化的對象。而且,只要可以初始化任何對象,就可以將 Null 值分配給任何類型。



          因此,Java 允許下一個分配:?



          這里有什么問題?對象未初始化,因此它們指向空引用。看似很自然,實則是 萬惡之源。



          4

          弱類型安全的后果


          就 Java 而言,Null 和真實對象之間沒有區(qū)別,它會導(dǎo)致不可能的操作,如下面的:不可能的操作。



          所以,從編譯器的角度來看,沒有錯。Null 屬于 String 類型,Java 甚至不會打印警告。實際上,您甚至可以編譯下一個代碼:可編譯的代碼。



          但是,一旦我們運(yùn)行這個程序,它將失敗并出現(xiàn) NullPointerException:


          空指針異常



          5

          NullPointerException 定義


          NullPointerException 是一個運(yùn)行時異常,當(dāng) Java 嘗試調(diào)用真實對象上的任何方法但在運(yùn)行時該對象引用 Null 引用時會引發(fā)該異常。您可以在本文中找到有關(guān)異常及其性質(zhì)的更多詳細(xì)信息。



          6

          為什么 NullPointerException 是最常見的異常??


          開發(fā)人員是人類,總是習(xí)慣于忘記一些事情。因此,他們錯過了:


          • 初始化對象

          • 驗證對象?


          沒有治愈人性的方法,也與它無關(guān)。避免NPE的實用方法是什么?讓我們在下面回顧一個示例并嘗試修復(fù)它。??



          7

          NullPointerException


          在我們的示例中,我們有一個帶有地址字段的用戶對象。潛在地,它們都可能為空。讓我們看看如何避免 NullPointerException。?


          潛在的空指針異常



          8

          使用?!= Null 檢查避免


          現(xiàn)在,讓我們通過簡單的檢查來防止這個問題,而不是空檢查:


          簡單檢查


          我們可以改進(jìn)這個解決方案嗎?


          是的,我們可以使用 Optional。使用 map 函數(shù),我們可以編寫與前面的語句類似的等價物:?



          與簡單的空檢查相比,可選是否提供好處?是的,它確實。Optional 向我們保證我們在 ifPresent lambda 中使用的數(shù)據(jù)不為空。但是,如果用戶或地址為空怎么辦?然后, ifPresent 將被靜默忽略。?


          而且,即使我們忘記使用 Optional 功能,這個想法也會突出顯示 .get() ,提醒我們?yōu)樵O(shè)計提供空檢查。?




          9

          Optional 為什么不那么受歡迎?

          ?

          可選功能在 Java 1.8 中發(fā)布,但并沒有被廣泛使用。有幾個原因:


          • 它非常冗長并且污染了代碼(我個人認(rèn)為這是主要原因,Java 本身非常冗長,而使用 Optional 它變得非常大)。

          • 目前還不清楚,在所有 map/flatmap/ifpresent 背后,你可能會失去邏輯的意義。所以丑陋的空檢查是簡單明了的。

          • Optional 本身可能會導(dǎo)致開發(fā)人員創(chuàng)建更多的 NPE,例如通過使用 Optional.of(nullable)。


          因此,出于上述原因,一些團(tuán)隊更喜歡使用空檢查。為了避免任何 NPE 異常,用一堆測試來覆蓋這樣的邏輯。



          10

          空檢查和可選它們是否解決了問題?


          上面顯示了兩個“解決方案”,它們真的是解決方案嗎?Null 檢查與 Optional 一起用于相同目的 - 為可能為 null 的數(shù)據(jù)提供驗證。另外,Optional 提醒開發(fā)者返回值可以為空。但是,總的來說,關(guān)鍵問題隱藏在人性中——忘記或錯過潛在的無效場景。我們需要一個解決方案來指出開發(fā)人員在編譯步驟中遺漏了什么。



          11

          @NotNull @Nullable


          我們需要一個解決方案,它可以在編譯步驟中讀取我們的代碼,并通知我們錯過了潛在的 NPE 場景。為此,我們可以使用 Java 注釋處理器。Java 注釋處理器有很多用途,但也可以用于我們的案例。在本文中,您可以找到一個如何使用注釋處理器來檢查可變性的示例。


          有幾個與 NPE 問題相關(guān)的注釋處理器。并非所有這些都是相同的,并且遵循完全不同的方法。



          12

          Lombok @NotNull 注解


          Lombok @NotNull Annotation 用于生成可以阻止執(zhí)行但僅在 Runtime 中的非空檢查。所以它不符合我們的目的。很快,這個注解做了接下來的事情:


          注解



          13

          使用檢查器框架


          Checker Framework提供了 @NonNull@Nullable 注釋以及可以識別潛在空檢查的編譯器處理器步驟。該框架可以通過強(qiáng)制開發(fā)人員指定 Nullability 來找到潛在的空值。因此,每當(dāng)您返回某些內(nèi)容時,您必須顯式聲明返回的結(jié)果可以是 Nullable 還是 NotNullable...讓我們看下一個示例:


          一個可能返回 Null 而不是 String 的簡單方法:



          現(xiàn)在,讓我們使用我們的 Checker 框架,看看它是否愿意編譯它:


          使用檢查器框架


          不,一點(diǎn)都不快樂。它說我們返回一個可能為空的字符串,并且它沒有用 @Nullable 注釋標(biāo)記。現(xiàn)在,讓我們將其標(biāo)記為@Nullable,并嘗試使用它:


          使用 @Nullable 注釋


          該框架會在該代碼中發(fā)現(xiàn)任何錯誤嗎?讓我們再次運(yùn)行編譯檢查:


          運(yùn)行編譯


          因此,它在第 19 行發(fā)現(xiàn)了一個潛在問題,我們嘗試在 Nullable 字符串上調(diào)用 .length()。讓我們使用 Null 檢查和可選的 ifPresent 來修復(fù)它:


          使用 Null 檢查和可選的 ifPresent 修復(fù)問題


          而且,編譯后,我們得到了一個成功的構(gòu)建:


          構(gòu)建成功


          ?

          15

          檢查器框架限制

          到目前為止,Checker Framework 顯示出良好的結(jié)果并突出了潛在的 NPE。但是,代價是什么?現(xiàn)在我們有義務(wù)通過@Nullable 方法標(biāo)記所有可能為Nullable 的方法。這似乎是一個強(qiáng)制性的步驟,我們無法避免。但是,這不是唯一的限制。讓我們創(chuàng)建一個簡單的類,其中包含兩個字段,其中一個是我們標(biāo)記為@NonNull 的字段:


          具有兩個字段的簡單類


          Checker Framework 會接受此代碼嗎??


          Checker Framework 強(qiáng)制我們有一個初始化 id 值的構(gòu)造函數(shù),例如:


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


          因此,F(xiàn)ramework 不僅識別了潛在的 NPE,還迫使我們遵循特定的要求或設(shè)計。其實這個要求很關(guān)鍵。而且,這是值得懷疑的。我們是否應(yīng)該為了適應(yīng)框架限制而犧牲這種開發(fā)靈活性?這是一個懸而未決的問題。要使用 Checker Framework,您可以在此處獲取我的示例:


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


          要運(yùn)行 Checker Framework,請運(yùn)行以下命令:


          mvn?clean compile


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


          Checker Framework 不是唯一的解決方案,Intellij Idea 提供了自己的注釋 @NotNull 和 @Nullable 以及嵌入在 IDE 插件中。不幸的是,我還沒有找到在 maven 編譯步驟中添加它的方法。因此,如果存在,請在評論中告訴我,我會對其進(jìn)行測試并將其添加到文章中。??


          ?

          16

          總結(jié)


          總結(jié)整篇文章,我建議如下:


          • 更喜歡 Optional 而不是傳遞 Null

          • 使用檢查器框架?


          老實說,在實踐中,Checker Framework 給您的開發(fā)帶來了限制。如果我必須實現(xiàn)自己的解決方案并且它必須在生產(chǎn)中保持穩(wěn)定,即使我必須擺脫 Lombok 甚至 Builder Pattern,我也會使用 Checker Framework。


          瀏覽 43
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  丁香五月婷婷av影院 | 国产一级精品黄色录像 | 岛国免费小电影在线 | 性爱基地 | 国产免费一区二区三区四区六区在线 |