我賭你不清楚Spring中關于Null的這些事
之前一直在某些代碼中看到過使用@Nullable 標注過的注釋,當時也沒有在意到底是什么意思,之后忍不住去調查一番,這篇文章來談談Spring中關于Null的那些事。
在Java中不允許你使用類型表示其null的安全性,但Spring Framework 現(xiàn)在在org.sprinngframework.lang包提供以下注釋,以便聲明API和字段的可空性:
- @Nullable: 用于指定參數(shù)、返回值或者字段可以作為null的注釋。
- @NonNull: 與上述注釋相反,表明指定參數(shù)、返回值或者字段不允許為null。(不需要@NonNullApi和@NonNullFields適用的參數(shù)/返回值和字段)
- @NonNullApi: 包級別的注釋聲明非null作為參數(shù)和返回值。
- @NonNullFields:包級別的注釋聲明字段默認非空
Spring Framework 本身利用了上面這幾個注釋,但它們也可以運用在任何基于Spring的Java 項目中,以聲明空安全api 和 空安全字段。尚未支持泛型和數(shù)組元素的可空性,但應該也會在后期版本中支持這倆。
Spring Null-Safety出現(xiàn)在Spring5中,讓我們更方便的編寫空安全的代碼,這叫做null-safety,null-safety不是讓我們逃脫不安全的代碼,而是在編譯時產(chǎn)生警告。 此類警告可以在運行時防止災難性空指針異常(NPE)。
@NonNull
@NonNull注釋是null-safety的所有注釋中最重要的一個,我們可以使用此注釋在期望對象引用的任何地方聲明非空約束:字段、方法參數(shù)或者方法返回值。
先來看一個例子
public class Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
if(null != null && name.isEmpty()){
name = null;
}
this.name = name;
}
}
上述代碼對name的校驗是有效的,但是存在一個缺陷,如果name被設置為null的話,那么當我們使用name的時候,就會以NullPointerException來結尾。
使用@NonNull
Spring 的null-safety特性能夠允許idea或者eclipse報告這個潛在的威脅,例如,如果我們用IDEA對屬性加上@NonNull會出現(xiàn)如下的效果。

奇怪,并沒有什么變化啊,沒看見有潛在的安全提示啊,那是因為你沒有在idea進行設置。
設置安全檢查
如果你也沒有提示的話,可以通過如下的方式設置安全檢查:

如果還不好使的話,那就在右側 configuration annotations 添加一下 @NonNull和 @Nullable 所在的jar包,如下:

添加上,打上 ✅ 即可看到如下效果。

現(xiàn)在fullName 已經(jīng)被@NonNull 注釋添加編譯器檢查null值的功能了!
測試一下,可以把@NonNull 注釋去掉,你的鼠標再放在fullName 上,就沒有這句提示了。
@NonNullFields
@NonNull 注解能夠幫助你確保null-safety。然而,如果此注釋直接裝飾所有的字段的話,就會污染整個代碼庫。
Spring提供了另外一個不允許為null的注解 — @NonNullFields。這個注解適合用在包級別上,通知我們的開發(fā)工具注釋包中所有的字段,默認的,不允許為null
新建一個Parent類,并在該類所屬包下創(chuàng)建一個名為package-info.java的類,創(chuàng)建的不是Java類,而是創(chuàng)建的file,名為package-info.java,如下
package-info.java
@NonNullFields package com.nullsafety.demo.pojo; import org.springframework.lang.NonNullFields;
新建一個Parent.java 類
public class Parent {
private String son;
private String age;
private String name;
public void setSon(String son) {
if(son != null && son.isEmpty()){
son = null;
}
this.son = son;
}
public void setAge(String age) {
if(age != null && age.isEmpty()){
age = null;
}
this.age = age;
}
public void setName(String name) {
if(name != null && name.isEmpty()){
name = null;
}
this.name = name;
}
}
package-info.java 中的@NonNullFields能夠對Parent類中所有的屬性起作用,把鼠標放在任意一個屬性上,會出現(xiàn)編譯期檢查的提示

@Nullable
@NonNullFields注釋通常比@NonNull更好,因為它有助于減少樣板。 但是,有時我們想要從包級別指定的非null約束中免除某些字段,這時候就會使用到@Nullable注解
改造一下Person.java,Person.java 與pack-info.java 處于同一包下
public class Person {
@NonNull
private String fullName;
@Nullable
private String nickName;
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
if(nickName != null && nickName.isEmpty()){
nickName = null;
}
this.nickName = nickName;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
if(fullName != null && fullName.isEmpty()){
fullName = null;
}
this.fullName = fullName;
}
}
在這種情況下,我們使用@Nullable注釋來覆蓋字段上@NonNullFields的語義。
@NonNullApi
@NonNullFields注釋僅適用于其名稱所示的字段。 如果我們想對方法的參數(shù)和返回值產(chǎn)生相同的影響,我們需要@NonNullApi。
添加 @NonNullApi和 @NonNullFields 在 configure annotations 中,并選用NonNullApi

與@NonNullFields一樣,我們需要在package-info.java 中定義@NonNullApi
package-info.java
@NonNullApi @NonNullFields package com.nullsafety.demo.pojo; import org.springframework.lang.NonNullApi; import org.springframework.lang.NonNullFields;
加上如下注釋后的效果如下: 可以在返回值的時候接受到編譯期的提示。

結語
看完文章,你至少應該了解@NonNull, @Nullable, @NonNullFields, @NonNullApi四個注解和各自的作用范圍以及如何設置編譯期的Null-safety檢查。
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Jmeter壓力測試簡單教程(包括服務器狀態(tài)監(jiān)控)
Jmeter是一個非常好用的壓力測試工具。Jmeter用來做輕量級的壓力測試,非常合適,本文詳細的介紹了Jmeter的使用,感性的可以了解一下2021-11-11
JDK源碼之線程并發(fā)協(xié)調神器CountDownLatch和CyclicBarrier詳解
我一直認為程序是對于現(xiàn)實世界的邏輯描述,而在現(xiàn)實世界中很多事情都需要各方協(xié)調合作才能完成,就好比完成一個平臺的交付不可能只靠一個人,而需要研發(fā)、測試、產(chǎn)品以及項目經(jīng)理等不同角色人員進行通力合作才能完成最終的交付2022-02-02
Java實現(xiàn)的模糊匹配某文件夾下的文件并刪除功能示例
這篇文章主要介紹了Java實現(xiàn)的模糊匹配某文件夾下的文件并刪除功能,涉及java針對目錄與文件的遍歷、匹配、判斷、刪除等相關操作技巧,需要的朋友可以參考下2018-02-02
Spring AOP之@Around,@AfterReturning使用、切不進去的解決方案
這篇文章主要介紹了Spring AOP之@Around,@AfterReturning使用、切不進去的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05
ConcurrentModificationException日志關鍵字報警思考分析
本文將記錄和分析日志中的ConcurrentModificationException關鍵字報警,還有一些我的思考,有需要的朋友可以借鑒參考下,希望能夠有所幫助2023-12-12
深入分析Comparable與Comparator及Clonable三個Java接口
接口不是類,而是對類的一組需求描述,這些類要遵從接口描述的統(tǒng)一格式進行定義,這篇文章主要為大家詳細介紹了Java的Comparable,Comparator和Cloneable的接口,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-05-05

