
程式員,如果系統突然報了一個空指標例外,你肯定像吞了一只蒼蠅一樣尷尬,
那么如何在日常開發程序中降低NPE?
| 問題 | 回答 |
|---|---|
| 現狀 | 回傳空值會出現大量的空指標例外 |
| 目的 | 改進方法的回傳值,降低出現空指標例外 |
| 實作路徑 | 方法回傳空集合或者空陣列 |
跟我來!
背景
下面的方法看起來很常見,
private final List<Chesse> chessesInStock= ...
public List<Cheese> getCheeses(){
return cheesesInStock.isEmpty()?null:new ArrayList<>(cheesesInStock);
}
假如你去購買芝士的時候沒有可用的芝士,似乎沒有理由特別指出這種場景,
但是你這么做的話,客戶端需要添加額外代碼來處理可能回傳空值的情況,示例代碼如下:
List<Cheese> cheeses = shop.getCheeses();
if(cheses != null && cheeses.contains(Cheese.STILTON)){
System.out.println("jolly good");
}
每一個回傳空值的方法都使用上面這種處理方式,應該替換為回傳一個空集合或者空陣列,
這是一種錯誤的趨勢,因為程式員些客戶端代碼可能會忘記寫特殊代碼來處理回傳的空值,
這個錯誤可能會持續很長時間,因為這樣的方法通常會回傳一個或多個物件,
不回傳空集合空陣列的爭論
回傳空值替換為回傳空容器也會使得方法的實作變得復雜,
通常爭論的是:回傳空值比回傳空集合更好是因為創建一個空的容器有性能消耗,
這個論點不對,原因有兩點:
一,沒有必要擔心性能除非有證據顯示創建一個空容器整的有損性能;
二,你可以回傳一個空集合或者陣列而不用創建它們,
回傳空集合
下面是一個典型的代碼回傳一個可能的空集合,通常,這就是你所需要的,
public List<Cheese> getCheeses(){
return new ArrayList<>(cheeseInStock);
}
沒有證據證明創建一個空集合會有損性能,你可以回傳一個相同的不可變空集合來避免創建空集合,因為不可變物件是可以被自由共享的,下面是使用代碼,
| 需求場景 | 代碼 |
|---|---|
| 空List | Collections.emptyList() |
| 空Set | Collections.emptySet() |
| 空Map | Collections.emptyMap() |
但是記住,以上這些操作是只是優化,很少被呼叫,如果你認為你需要它,在呼叫前后進行性能對比,確保它真的有用,
public List<Cheese> getCheeses(){
return cheesesInStock.isEmpty()?Collections.emptyList():new ArrayList<>(cheesesInStock);
}
回傳空陣列
使用陣列的場景跟集合是相同的,永遠不要回傳空值,應該回傳一個長度位0的陣列,常常,你應該簡單的回傳一個有適當長度的陣列,也許長度是0,
注意我們傳遞一個長度為0的陣列到toArray方法中來代表期望的回傳型別;
public Cheese[] getCheeses(){
return cheesesInStock.toArray(new Cheese[0]);
}
如果你認為創建一個長度為0的陣列會降低性能,你可以回傳同一個長度為0的陣列,因為所有長度為0的陣列都是不可變的;
private static final Cheese[] EMPTY_ARRAY= new Cheese[0];
public Cheeses[] getCheeses(){
return cheesesInStock.toArray(EMPTY_ARRAY);
}
在優化版本中,我們傳遞了同一個空的陣列到每一個toArray的呼叫,這個陣列將會從getCheeses回傳,無論cheesesInStock是不是空的,不要期望預分配陣列可以提高性能,研究顯示這是適得其反的,
return cheesesInStock.toArray(new Cheese[cheesesInStock.size()]);
小結
如果你只能記住一句話:回傳空集合或者陣列而不要回傳空值,
回傳空值會讓你的API更難使用并且更容易出錯,并且無性能優勢;

原創不易,關注誠可貴,轉發價更高!轉載請注明出處,讓我們互通有無,共同進步,歡迎溝通交流,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/52316.html
標籤:Java
