Immutable empty collections and iterators

Discover the java.util.Collections class's support for immutable empty collections and iterators

A collection of marigolds.
Jim Capaldi (CC BY-SA 2.0)

Have you ever wondered why the java.util.Collections class includes various "empty" class methods, which return immutable empty collections and immutable empty iterators? This post answers this question.

An immutable empty list of flowers

The Collections class's various "empty" class methods offer a useful alternative to returning null (and avoiding potential java.lang.NullPointerExceptions from being thrown) in certain contexts. Listing 1 presents the source code to an application that demonstrates the benefit of an immutable empty list.

Listing 1. Empty and nonempty Lists of Flowers

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

class Flowers
{
   private List<String> flowers;

   Flowers()
   {
      flowers = Collections.emptyList();
   }

   Flowers(String... flowerNames)
   {
      flowers = new ArrayList<String>();
      for (String flowerName: flowerNames)
         flowers.add(flowerName);
   }

   @Override
   public String toString()
   {
      return flowers.toString();
   }
}

public class EmptyListDemo
{
   public static void main(String[] args)
   {
      Flowers flowers = new Flowers();
      System.out.println(flowers);
      flowers = new Flowers("Rose", "Violet", "Marigold");
      System.out.println(flowers);
   }
}

Listing 1 declares a Flowers class that stores the names of various flowers in a list. This class provides two constructors: a noargument constructor and a constructor that takes a variable number of java.lang.String arguments identifying various flowers.

The noargument constructor invokes <T> List<T> emptyList() to initialize its private flowers field to an empty java.util.List of String -- emptyList() is a generic method and the compiler infers its return type from its context.

If you're wondering about the need for emptyList(), examine the toString() method. Notice that this method evaluates flowers.toString(). If you didn't assign a reference to an empty List<String> to flowers, flowers would contain the null reference (the default value for this instance field when the object is created), and a NullPointerException object would be thrown when attempting to evaluate flowers.toString().

Compile Listing 1 as follows:

javac EmptyListDemo.java

Run the resulting application as follows:

java EmptyListDemo

You should observe the following output:

[]
[Rose, Violet, Marigold]

An immutable empty iterator of to-do tasks

Most of the "empty" methods return immutable empty collections, but three methods return immutable empty iterators: <T> Enumeration<T> emptyEnumeration() (classic iteration method), <T> Iterator<T> emptyIterator(), and <T> ListIterator<T> emptyListIterator(). Listing 2 demonstrates the need for an immutable empty iterator.

Listing 2. NullPointerException arising from the null reference in todoList

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

class ToDo
{
   private String task;
   private String date;

   ToDo(String task, String date)
   {
      this.task = task;
      this.date = date;
   }

   @Override
   public String toString()
   {
      return task + ": "+ date;
   }
}

class ToDoList
{
   private List<ToDo> todoList;

   void add(ToDo todo)
   {
      if (todoList == null)
         todoList = new ArrayList<>();
      todoList.add(todo);
   }

   public Iterator<ToDo> iterator()
   {
      return todoList.iterator();
   }
}

public class EmptyIteratorDemo
{
   public static void main(String[] args)
   {
      ToDoList todoList = new ToDoList();
      //todoList.add(new ToDo("Mow the lawn", "April 5, 10 AM"));
      Iterator<ToDo> todos = todoList.iterator();
      while (todos.hasNext())
         System.out.println(todos.next());
   }
}

Listing 2 presents ToDo and ToDoList classes that describe individual and lists of to-do tasks in terms of task name and date by which the task should have been performed. ToDoList's add() method lazily initializes the list. Unfortunately, this lazy initialization can result in a thrown NullPointerException object.

NullPointerException arises when toDoList.iterator() in ToDoList's iterator() method is executed and toDoList contains the null reference because add() hasn't been called. Compiling Listing 2 (javac EmptyIteratorDemo.java) and running the application (java EmptyIteratorDemo) results in the following output:

Exception in thread "main" java.lang.NullPointerException
	at ToDoList.iterator(EmptyIteratorDemo.java:37)
	at EmptyIteratorDemo.main(EmptyIteratorDemo.java:47)

You can avoid the exception by uncommenting the toDoList.add() call in the main() method. Better still, you can modify ToDoList's iterator() method to return the result of calling Collections.emptyIterator() when toDoList contains the null reference, as follows:

public Iterator<ToDo> iterator()
{
   return (todoList != null) ? todoList.iterator() 
                             : Collections.emptyIterator();
}

Conclusion

The Collections class's various "empty" class methods can help you write safer code that avoids thrown NullPointerExceptions. They can also help you write more streamlined code because you don't always have to test for null references. For example, Listing 1's toString() method specifies return flowers.toString(); instead of having to specify the longer return (flowers != null) ? flowers.toString() : "";.

download
Get the source code for this post's applications. Created by Jeff Friesen for JavaWorld

The following software was used to develop the post's code:

  • 64-bit JDK 8u60

The post's code was tested on the following platform(s):

  • JVM on 64-bit Windows 8.1

This story, "Immutable empty collections and iterators" was originally published by JavaWorld.

Copyright © 2016 IDG Communications, Inc.

InfoWorld Technology of the Year Awards 2023. Now open for entries!