It is not
uncommon to see methods that look something like this:
private final List<Cheese> 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(cheeses).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 an empty (zero-length) array or
collection. It is errorprone, because the programmer writing the client might
forget to write the specialcase code to handle a null return.
It is
sometimes argued that a null return value is preferable to an empty 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 55). 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
15). In fact, this is exactly what happens when you use the standard idiom for
dumping items from a collection into a typed array:
// The right way to return an array from a
collection
private final List<Cheese> cheesesInStock = ...;
private static final Cheese[] EMPTY_CHEESE_ARRAY = new
Cheese[0];
/**
* @return an array containing all of the cheeses in the
shop.
*/
public Cheese[] getCheeses() {
return cheesesInStock.toArray(EMPTY_CHEESE_ARRAY);
}
In this idiom,
an empty-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 zero-length input array, and the
specification for Collection.toArray(T[]) guarantees
that the input array will be returned if it is large enough to hold the
collection. Therefore the idiom never allocates an empty array.
In similar
fashion, a collection-valued method can be made to return the same immutable
empty collection every time it needs to return an empty collection. The Collections.emptySet, emptyList, and emptyMap methods provide exactly what you need, as
shown below:
// The right way to return a copy of a collection
public List<Cheese> getCheeseList() {
if (cheesesInStock.isEmpty())
return Collections.emptyList(); // Always returns same
list
else
return new ArrayList<Cheese>(cheesesInStock);
}
In summary, there is no
reason ever to return null from an array-
or collection-valued method instead of returning an empty array or collection. The
null-return 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.
Reference: Effective Java 2nd Edition by Joshua Bloch