1. 程式人生 > >Effective Java 第三版——54. 返回空的數組或集合不要返回null

Effective Java 第三版——54. 返回空的數組或集合不要返回null

ogr 基於 mage 第三版 this getc get ise eal

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