emptyList(), emptySet(), emptyMap()

December 08, 2009

This is the first in a series of posts on under-utilized Java collection types and idioms worth adding to your Java vocabulary.

Top 5 Under-utilized Java Collections

#1: Empty Collections

Every Java programmer has at least once declared a constant to represent an empty collection. It might have looked something like this:
static final List<Result> NO_RESULTS = new ArrayList<Result>(0);

This is unnecessary. Since at least 1.3, java.util.Collections has had built-in immutable empty collections:
   Collections.EMPTY_LIST
Collections.EMPTY_SET
Collections.EMPTY_MAP

With the introduction of generics in Java 5, Collections got factory methods that return empty collections of whatever type you need:
   List<Result> list = Collections.emptyList();
Set<Result> set = Collections.emptySet();
Map<String, Result> map = Collections.emptyMap();

Because of type erasure, these methods don’t actually need to create a new collection with each invocation. All they do is return a reference to an empty collection that’s already sitting there in memory.

These methods will make your code more readable (especially if you statically import them), more memory efficient (fewer object allocations), and smaller (no need for constants to represent empty collections).

Here’s a special-case return value example:
   List<Foo> fetchFoos(Collection<Id<Foo>> ids) {
if (ids.isEmpty()) {
return emptyList();
}
...
}

If you’re concerned about returning immutable empty collections, since callers might want to add to them, I’d generally recommend changing any such callers to make a copy first. The Google Collections copying factory methods come in handy here:
   List<Bar> bars = Lists.newArrayList(foo.getBars()));
bars.addAll(otherBars);

Directly modifying a returned collection is a pattern that I try to limit to private, protected, or factory methods.

And here’s a test assertion example:
   assertEquals(emptyList(), foo.getBars());

// Type parameters are unnecessary for Junit's assertEquals method,
// but are often needed when passing empty collections elsewhere.
assertEquals(Collections.<Bar>emptyList(), foo.getBars());

// This assertion is equivalent, but doesn't produce helpful output
// when it fails.
assertTrue(foo.getBars().isEmpty());

Stay tuned for the next installment…