Friday, October 23, 2009

Item 27: Return zero-length arrays, not nulls




< BACKCONTINUE >


Item 27: Return zero-length arrays, not nulls


It is not uncommon to see methods that look something like this:





private List cheesesInStock = ...;

/**
* @return an array containing all of the cheeses in the shop,
* or null if no cheeses are available for purchase.
*/
public Cheese[] getCheeses() {
if (cheesesInStock.size() == 0)
return null;
...
}


There is no reason to make a special case for the situation where no cheeses are available for purchase. Doing so requires extra code in the client to handle the null return value, for example:





Cheese[] cheeses = shop.getCheeses();
if (cheeses != null &&
Arrays.asList(shop.getCheeses()).contains(Cheese.STILTON))
System.out.println("Jolly good, just the thing.");


instead of:





if (Arrays.asList(shop.getCheeses()).contains(Cheese.STILTON))
System.out.println("Jolly good, just the thing.");


This sort of circumlocution is required in nearly every use of a method that returns null in place of a zero length array. It is error prone, as the programmer writing the client might forget to write the special-case code to handle a null return. Such an error may go unnoticed for years, as such methods usually return one or more objects. Less significant, but still worthy of note, returning null in place of a zero length array also complicates the array-returning method itself.



It is sometimes argued that a null return value is preferable to a zero-length array because it avoids the expense of allocating the array. This argument fails on two counts. First, it is inadvisable to worry about performance at this level unless profiling has shown that the method in question is a real contributor to performance problems (Item 37). Second, it is possible to return the same zero-length array from every invocation that returns no items because zero-length arrays are immutable and immutable objects may be shared freely (Item 13). In fact, this is exactly what happens when you use the standard idiom for dumping items from a collection into a typed array:





private List cheesesInStock = ...;

private final static Cheese[] NULL_CHEESE_ARRAY = new Cheese[0];

/**
* @return an array containing all of the cheeses in the shop.
*/
public Cheese[] getCheeses() {
return (Cheese[]) cheesesInStock.toArray(NULL_CHEESE_ARRAY);
}


In this idiom, a zero-length array constant is passed to the toArray method to indicate the desired return type. Normally the toArray method allocates the returned array, but if the collection is empty, it fits in the input array, and the specification for Collection.toArray(Object[]) guarantees that the input array will be returned if it is large enough to hold the collection. Therefore the idiom never allocates a zero-length array but instead reuses the "type-specifier constant."



In summary, there is no reason ever to return null from an array-valued method instead of returning a zero-length array. This idiom is likely a holdover from the C programming language, in which array lengths are returned separately from actual arrays. In C, there is no advantage to allocating an array if zero is returned as the length.





< BACKCONTINUE >

No comments: