NullAway 是一個幫助消除 Java 程式碼中的NullPointerException
(NPE) 的工具。若要使用 NullAway,請先在程式碼中欄位、方法參數或傳回值可能為null
位置新增@Nullable
註解。給定這些註釋,NullAway 會執行一系列基於類型的本機檢查,以確保程式碼中取消引用的任何指標都不能為null
。 NullAway 類似於 Kotlin 和 Swift 語言中基於類型的可空性檢查,以及 Java 的 Checker Framework 和 Eradicate null 檢查器。
NullAway速度很快。它是作為 Error Prone 的插件構建的,可以在程式碼的每個版本上運行。根據我們的測量,運行 NullAway 的建置時間開銷通常低於 10%。 NullAway 也很實用:它不會阻止程式碼中所有可能的 NPE,但它會捕捉我們在生產中觀察到的大多數 NPE,同時施加合理的註釋負擔,從而「物有所值」。
NullAway 要求您使用 Error Prone 版本 2.14.0 或更高版本建立程式碼。請參閱 Error Prone 文檔,以了解有關 Error Prone 入門以及與建置系統整合的說明。以下說明假設您正在使用 Gradle;有關其他建置系統的討論,請參閱文件。
若要將 NullAway 整合到您的非 Android Java 專案中,請將以下內容新增至您的build.gradle
檔案:
plugins {
// we assume you are already using the Java plugin
id " net.ltgt.errorprone " version " <plugin version> "
}
dependencies {
errorprone " com.uber.nullaway:nullaway:<NullAway version> "
// Some source of nullability annotations; JSpecify recommended,
// but others supported as well.
api " org.jspecify:jspecify:1.0.0 "
errorprone " com.google.errorprone:error_prone_core:<Error Prone version> "
}
import net.ltgt.gradle.errorprone.CheckSeverity
tasks . withType( JavaCompile ) {
options . errorprone {
check( " NullAway " , CheckSeverity . ERROR )
option( " NullAway:AnnotatedPackages " , " com.uber " )
}
// Include to disable NullAway on test code
if (name . toLowerCase() . contains( " test " )) {
options . errorprone {
disable( " NullAway " )
}
}
}
讓我們逐步瀏覽一下這個腳本。 plugins
部分引入了 Gradle Error Prone 插件以進行 Error Prone 整合。
在dependencies
中,第一個errorprone
行載入 NullAway, api
行載入 JSpecify 函式庫,該函式庫提供適當的可空性註釋,例如org.jspecify.annotations.Nullable
。 NullAway 允許使用任何@Nullable
註釋,因此,例如,來自 AndroidX 註釋庫或 JetBrains 註釋的@Nullable
也可以。第二個errorprone
行設定使用的 Error Prone 版本。
最後,在ta tasks.withType(JavaCompile)
部分,我們將一些設定選項傳遞給NullAway。首先check("NullAway", CheckSeverity.ERROR)
將 NullAway 問題設定為錯誤等級(它相當於-Xep:NullAway:ERROR
標準 Error Prone 參數);預設情況下 NullAway 會發出警告。然後, option("NullAway:AnnotatedPackages", "com.uber")
(相當於-XepOpt:NullAway:AnnotatedPackages=com.uber
標準易錯參數)告訴 NullAway com.uber
命名空間下的套件中的原始碼應該是檢查null 取消引用和@Nullable
註釋的正確使用,並且應假定這些包中的類文件具有@Nullable
的正確使用(有關更多詳細信息,請參閱文檔)。 NullAway 至少需要AnnotatedPackages
配置參數才能運行,以便區分帶註解和未註解的程式碼。有關其他有用的配置選項,請參閱配置文件。若要更簡單設定 NullAway 選項,請使用 Gradle NullAway 外掛程式。最後,我們將展示如何在需要時在測試程式碼上停用 NullAway。
我們建議解決 Error Prone 報告的所有問題,特別是那些報告為錯誤(而不是警告)的問題。但是,如果您想嘗試 NullAway 而不執行其他容易出錯的檢查,則可以使用options.errorprone.disableAllChecks
(相當於在 NullAway 特定參數之前將"-XepDisableAllChecks"
傳遞給編譯器)。
Gradle Error Prone 插件的 3.0.0 及更高版本不再支援 Android。因此,如果您使用的是此外掛程式的最新版本,則需要添加一些進一步的配置才能運行 Error Prone 和 NullAway。我們的範例應用程式build.gradle
檔案展示了執行此操作的一種方法,但您的 Android 專案可能需要調整。或者,2.x 版本的 Gradle Error Prone 插件仍然支援 Android,並且可能仍然適用於您的專案。
除此之外,與Java配置相比,可以刪除JSpecify依賴;您可以使用 AndroidX 註解庫中的androidx.annotation.Nullable
註解。
一些註解處理器(例如 Dagger 和 AutoValue)將程式碼產生到與您自己的程式碼相同的套件命名空間中。當將 NullAway 設定為上面建議的ERROR
等級時,這可能會導致問題,因為產生的程式碼中的錯誤將阻止建置。目前解決此問題的最佳解決方案是使用 Error Prone 2.1.3 中新增的-XepExcludedPaths
選項在產生的程式碼上完全停用 Error Prone(此處記錄,在 Gradle 中使用options.errorprone.excludedPaths=
)。若要使用,請找出哪個目錄包含產生的程式碼,並將該目錄新增至排除的路徑正規表示式中。
Dagger 使用者註意:2.12 之前的 Dagger 版本可能會與 NullAway 產生不良互動;見這裡。請更新至 Dagger 2.12 以修復該問題。
與上述其他註解處理器不同,Lombok 修改了它處理的程式碼的記憶體中 AST,這是與 Error Prone 以及 NullAway 不相容的根源。
我們不特別推薦將 NullAway 與 Lombok 一起使用。然而,NullAway 編碼了常見 Lombok 註釋的一些知識,我們確實盡力實現相容性。特別是,應該支援@lombok.Builder
和@Data
類別等常見用法。
為了讓 NullAway 成功偵測記憶體中 Java AST 中 Lombok 產生的程式碼,必須將以下設定選項作為適用lombok.config
檔的一部分傳遞給 Lombok:
lombok.addLombokGeneratedAnnotation = true
這會導致 Lombok 將@lombok.Generated
加入到它產生的方法/類別中。 NullAway 將忽略(即不檢查)此生成程式碼的實現,將其視為未註解的。
讓我們透過一個簡單的程式碼範例來看看 NullAway 如何運作:
static void log ( Object x ) {
System . out . println ( x . toString ());
}
static void foo () {
log ( null );
}
這段程式碼有缺陷:當呼叫foo()
時,後續對log()
呼叫將會失敗並出現 NPE。您可以透過執行以下命令在 NullAway 範例應用程式中看到此錯誤:
cp sample/src/main/java/com/uber/mylib/MyClass.java.buggy sample/src/main/java/com/uber/mylib/MyClass.java
./gradlew build
預設情況下,NullAway 假定每個方法參數、傳回值和欄位都是非 null 的,即永遠無法為其指派null
值。在上面的程式碼中, log()
的x
參數被假定為非空。因此,NullAway 會報告以下錯誤:
warning: [NullAway] passing @Nullable parameter 'null' where @NonNull is required
log(null);
^
我們可以透過允許將null
傳遞給log()
並使用@Nullable
註解來修復此錯誤:
static void log ( @ Nullable Object x ) {
System . out . println ( x . toString ());
}
透過這個註釋,NullAway 指出了可能的 null 取消引用:
warning: [NullAway] dereferenced expression x is @Nullable
System.out.println(x.toString());
^
我們可以透過添加空檢查來修復此警告:
static void log ( @ Nullable Object x ) {
if ( x != null ) {
System . out . println ( x . toString ());
}
}
透過此更改,所有 NullAway 警告均已修復。
有關 NullAway 檢查、錯誤訊息和限制的更多詳細信息,請參閱我們的詳細指南。
如果您對如何使用 NullAway 有任何疑問,請隨時開啟 GitHub 問題。或者,您可以加入 NullAway Discord 伺服器並在那裡向我們提問。
我們希望您能為 NullAway 做出貢獻!請注意,建立拉取請求後,系統會要求您簽署我們的 Uber 貢獻者授權協議。
NullAway 已獲得 MIT 許可。有關詳細信息,請參閱 LICENSE.txt 檔案。