Effective Java 第三版——54. 返回空的數組或集合不要返回null
Tips
書中的源代碼地址:https://github.com/jbloch/effective-java-3e-source-code
註意,書中的有些代碼裏方法是基於Java 9 API中的,所以JDK 最好下載 JDK 9以上的版本。
54. Effective Java 第三版——54. 返回空的數組或集合不要返回null
看到類似這樣的方法並不罕見:
// Returns null to indicate an empty collection. Don't do this! private final List<Cheese> cheesesInStock = ...; /** * @return a list containing all of the cheeses in the shop, * or null if no cheeses are available for purchase. */ public List<Cheese> getCheeses() { return cheesesInStock.isEmpty() ? null : new ArrayList<>(cheesesInStock); }
沒有理由對沒有奶酪(Cheese)可供購買的情況進行特殊處理。這樣需要在客戶端做額外的代碼處理可能為null的返回值,例如:
List<Cheese> cheeses = shop.getCheeses();
if (cheeses != null && cheeses.contains(Cheese.STILTON))
System.out.println("Jolly good, just the thing.");
在幾乎每次使用返回null來代替空集合或數組的方法時,都需要使用這種迂回的方式。 它容易出錯,因為編寫客戶端的程序員可能忘記編寫特殊情況代碼來處理null返回。 多年來這種錯誤可能會被忽視,因為這種方法通常會返回一個或多個對象。 此外,返回null代替空容器會使返回容器的方法的實現變得復雜。
有時有人認為,null返回值比空集合或數組更可取,因為它避免了分配空容器的開銷。這個論點有兩點是不成立的。首先,除非測量結果表明所討論的分配是性能問題的真正原因,否則不宜擔心此級別的性能(條目67)。第二,可以在不分配空集合和數組的情況下返回它們。下面是返回可能為空的集合的典型代碼。通常,這就是你所需要的:
//The right way to return a possibly empty collection public List<Cheese> getCheeses() { return new ArrayList<>(cheesesInStock); }
如果有證據表明分配空集合會損害性能,可以通過重復返回相同的不可變空集合來避免分配,因為不可變對象可以自由共享(條目17)。下面的代碼就是這樣做的,使用了Collections.emptyList
方法。如果你要返回一個Set,可以使用Collections.emptySet
;如果要返回Map,則使用Collections.emptyMap
。但是請記住,這是一個優化,很少需要它。如果你認為你需要它,測量一下前後的性能表現,確保它確實有幫助:
// Optimization - avoids allocating empty collections
public List<Cheese> getCheeses() {
return cheesesInStock.isEmpty() ? Collections.emptyList()
: new ArrayList<>(cheesesInStock);
}
數組的情況與集合的情況相同。 永遠不要返回null,而是返回長度為零的數組。 通常,應該只返回一個正確長度的數組,這個長度可能為零。 請註意,我們將一個長度為零的數組傳遞給toArray
方法,以指示所需的返回類型,即Cheese []
:
//The right way to return a possibly empty array
public Cheese[] getCheeses() {
return cheesesInStock.toArray(new Cheese[0]);
}
如果你認為分配零長度數組會損害性能,則可以重復返回相同的零長度數組,因為所有零長度數組都是不可變的:
// Optimization - avoids allocating empty arrays
private static final Cheese[] EMPTY_CHEESE_ARRAY = new Cheese[0];
public Cheese[] getCheeses() {
return cheesesInStock.toArray(EMPTY_CHEESE_ARRAY);
}
在優化的版本中,我們將相同的空數組傳遞到每個toArray
調用中,當cheesesInStock
為空時,這個數組將從getCheeses
返回。不要為了提高性能而預先分配傳遞給toArray
的數組。研究表明,這樣做會適得其反[Shipilev16]:
// Don’t do this - preallocating the array harms performance!
return cheesesInStock.toArray(new Cheese[cheesesInStock.size()]);
總之,永遠不要返回null來代替空數組或集合。它使你的API更難以使用,更容易出錯,並且沒有性能優勢。
Effective Java 第三版——54. 返回空的數組或集合不要返回null