如果一個(gè)Java程序到處拋出NullPointerException,那么我們可能會(huì)各種吐槽代碼的質(zhì)量。但是我們的項(xiàng)目又經(jīng)常會(huì)拋出空指針異常,空指針異常必然常伴Java程序員。為此我們需要了解一些它嘍,NullPointerException是Java中一個(gè)常見的RuntimeException,正如阿里的Java開發(fā)手冊(cè)所說(shuō),對(duì)于Java程序員來(lái)說(shuō)防止NPE是一種基本素養(yǎng)。今天我們盤一下NullPointerException。
1 NullPointerException以及其產(chǎn)生的場(chǎng)景
Java中定義:在應(yīng)用程序中嘗試使用null時(shí)會(huì)拋出異常。
其中以下的情況會(huì)產(chǎn)生NullPointerException
- 調(diào)用空對(duì)象的方法,
- 訪問或者修改對(duì)象的字段值時(shí)
- 獲取一個(gè)空對(duì)象(數(shù)組)的長(zhǎng)度時(shí),
- 修改或者回取null數(shù)組的一個(gè)元素或者值時(shí)
- 拋出異常時(shí),拋出null。
以上是針對(duì)各種具體發(fā)生異常的情況,而對(duì)于日常使用過程中,可能拋出空指針異常的情景非常多,我們常用的手冊(cè)中提到了以下幾種NPE產(chǎn)生的實(shí)際使用場(chǎng)景。
- 返回類型為基本數(shù)據(jù)類型,return包裝數(shù)據(jù)類型的對(duì)象時(shí),自動(dòng)拆箱有可能產(chǎn)生NPE。
- 數(shù)據(jù)庫(kù)的查詢結(jié)果可能為null。
- 集合里的元素即使isNotEmpty,取出的數(shù)據(jù)元素也可能為null。
- 遠(yuǎn)程調(diào)用返回對(duì)象時(shí),一律要求進(jìn)行空指針判斷,防止NPE。
- 對(duì)于Session中獲取的數(shù)據(jù),建議進(jìn)行NPE檢查,避免空指針。
- 級(jí)聯(lián)調(diào)用obj.getA().getB().getC();一連串調(diào)用,易產(chǎn)生NPE。
自動(dòng)拆箱的NPE
如下代碼中,代碼邏輯出現(xiàn)問題的話,返回就是null。
public int count(){
Integer integer = null;
。。。。。。
return integer;
}
同理如下代碼也是同樣的問題,均屬于自動(dòng)拆裝箱時(shí)的NPE問題。
public static Boolean callSuccess(){
return null;
};
從集合取出的值直接使用會(huì)遇到NPE.
Map< String,String > map= new HashMap< >();
map.get("test").equals("test");
2 NPE處理以及如何避免
一般程序中需要處理NPE的地方隨處可見,常見的NPE預(yù)防介紹如下幾種方法。
2.1 如果是鏈?zhǔn)絞et這種推薦使用Optional進(jìn)行處理
如下代碼
public class Department {
private String departmentName;
private Company company;
...
}
public class Group {
private Department department;
...
}
public class Employee {
private String staffName;
private Group group;
...
}
如果程序中需要如此調(diào)用
employee.getGroup().getDepartment().getDepartmentName();
那么每一處均可能出現(xiàn)NullPointerException,如果我們寫成下面這樣。
if (employee != null){
if(employee.getGroup() != null){
if(employee.getGroup().getDepartment() != null){
String departmentName = employee.getGroup().getDepartment().getDepartmentName();
}
}
}
if嵌套大軍來(lái)襲,爾等還不下馬受死。
上述if嵌套看起來(lái)的確很不美觀,使用Optional可以比較容易的避免這些if判斷,代碼也會(huì)優(yōu)雅不少。
下面不管哪一層為null返回均為Default。
String s = Optional.ofNullable(employee)
.map(Employee::getGroup)
.map(Group::getDepartment)
.map(Department::getDepartmentName).orElse("Default");
或者使用如下方法,如果某一層為null則返回Supplier的執(zhí)行結(jié)果。
String s1 = Optional.ofNullable(employee)
.map(Employee::getGroup)
.map(Group::getDepartment)
.map(Department::getDepartmentName).orElseGet(() - > {
return "Supplier default";
});
2.2 主動(dòng)進(jìn)行參數(shù)檢查,對(duì)方法中傳入的參數(shù)進(jìn)行檢驗(yàn)
大部分的源碼中使用的基礎(chǔ)檢查均會(huì)檢查null
public static String testString(String str) throws Exception {
if (str == null){
throw new Exception("param can't be null");
}
return str;
}
2.3 在已知字符串上使用equals(),equalsIgnoreCase()等方法。
"knownObject".equals(unknownObject)
2.4 盡量避免方法中返回null
一些返回?cái)?shù)組或者List的方法,如果沒有值,盡量返回空集合,避免返回null。
2.5 新版本中Java輸出的NullPointException詳細(xì)信息
Java14 可以使用增強(qiáng)異常信息來(lái)查看NullPointerException
的詳細(xì)錯(cuò)誤信息。Java17已經(jīng)默認(rèn)開啟。
java -XX:+ShowCodeDetailsInExceptionMessages NPTDemo
使用Java17執(zhí)行如下語(yǔ)句及NullPointException的輸出
Map< String,String > map= new HashMap< >();
map.get("test").equals("test");
E:Javajdk-17.0.1bin >java NPTDemo
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because the return value of "java.util.Map.get(Object)" is null
at NPTDemo.main(NPTDemo.java:24)
-
數(shù)據(jù)
+關(guān)注
關(guān)注
8文章
6898瀏覽量
88832 -
代碼
+關(guān)注
關(guān)注
30文章
4750瀏覽量
68357 -
應(yīng)用程序
+關(guān)注
關(guān)注
37文章
3243瀏覽量
57603 -
null
+關(guān)注
關(guān)注
0文章
17瀏覽量
3919
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論