Thursday, 27 July 2017

Why do we require empty iterators?

Why do we require empty iterators?

In my previous post, I explained why do we require empty collections. I recommend you to go through the post "Why do we require empty collections?"

As you go through the Collections class, you can come across following method definitions.

Method
Description
public static <T> Enumeration<T> emptyEnumeration()
Returns an enumeration that has no elements.

public static <T> Iterator<T> emptyIterator()
Returns an iterator that has no elements.
public static <T> ListIterator<T> emptyListIterator()
Returns a list iterator that has no elements.

Can you think for some time, why do Collections class is providing the methods for empty iterators?


Ok let’s come to the point, suppose you had an Employees class, where it is maintaining all your employees information of your company. Your classes looks like below.
public class Employee {
 private int id;
 private String name;

 public Employee(int id, String name) {
  this.id = id;
  this.name = name;
 }

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

}

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

public class Employees {
 private List<Employee> employees;

 public Employees() {

 }

 public Employees(Employee... emps) {
  employees = Arrays.asList(emps);
 }

 public void printEmployees() {
  for (Employee emp : employees) {
   System.out.println(emp);
  }
 }

 public Iterator<Employee> getIterator() {
  return employees.iterator();
 }

}

As you closely observe the Employees class, there is a flaw in it. Suppose you created an instance of Employees class by using default constructor.

Employees employees  = new Employees();


Above statement don't initialize the instance variable 'employees', so it is null by default. When you call getIterator() method on Employees instance you will end up in NullPointerException.
import java.util.Iterator;

public class Test {

 public static void main(String args[]) {
  Employees emps = new Employees();

  Iterator<Employee> employees = emps.getIterator();
 }
}

Run Test.java, you will get following kind of output.

Exception in thread "main" java.lang.NullPointerException
 at test123.Employees.getIterator(Employees.java:25)
 at test123.Test.main(Test.java:10)

How to resolve the problem?
Check whether the instance variable 'employees' is null or not. If it is null, return emptyIterator, else return employees.iterator()

public Iterator<Employee> getIterator() {
 return (employees == null) ? Collections.emptyIterator() : employees.iterator();
}

Following is the updated version of Employees class.

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

public class Employees {
 private List<Employee> employees;

 public Employees() {

 }

 public Employees(Employee... emps) {
  employees = Arrays.asList(emps);
 }

 public void printEmployees() {
  for (Employee emp : employees) {
   System.out.println(emp);
  }
 }

 public Iterator<Employee> getIterator() {
  return (employees == null) ? Collections.emptyIterator() : employees.iterator();
 }

}

Re run Test.java, you won’t get any NullPointerException. There is a saying like; it is always better to return an empty collection/iterator instead of null. In these kind of scenarios, you can use empty iterators.

No comments:

Post a Comment