Return to the lecture notes index

Lecture #14 (February, 15 2006)

Iterators

So far we have written a number of methods to perform operations on both Singly Linked Lists and Doubly Linked Lists. These public methods include several variations on insertions, removals and finds. However, another thing a programmer will often want to do with a LinkedList is to Iterate through each item. This is easy to do from within the class itself, since we would have direct access to the Node subclass. We could just keep calling their getNext() methods to walk through the list.

However, if we are just using the LinkedList class in another program, we're out of luck. Since the Node class is private, we have no access to the nodes themselse or their getNext() methods.

This is where Iterators come in. What we want is to be able to write code like the following.

// Create a new Doubly Linked List
DoublyLinkedList dll = new DoublyLinkedList();

// *************************************
// **** Insert stuff into the list  ****
// *************************************

// Get an iterator for our list
Iterator i = dll.Iterator();

// Iterate through the list
while(i.hasNext()) {
	Object nextObject = i.next();
}

Java includes an Iterator Interface that requires every Iterator to contain certain methods, including next() and hasNext(), which are used above. The following methods are required by the Iterator Interface.

- public boolean hasNext() : The hasNext() method returns true if there are more elements in the list to iterate through, and false otherwise.

- public Object next() : The next method returns the next element in the list. We should be careful and only use this in conjuction with the hasNext() method or a try catch statement, as the next() method will throw an exception if there are no more elements left.

- public void remove() : The remove method should remove the last item returned by the next() method. This operation is optional, and we won't be using it in the class for now. So you should know that it is a part of the Iterator Interface, but for now, we are only concerned about next() and hasNext(). If we don't want to use a remove() method, we can just have it throw the UnsupportedOperationException.

So we want to write an Iterator for the Doubly Linked List we made in class. So first, we need to create a DoublyLinkedListIterator class that implements the Iterator interace. However, we immediately run into the problem of where to put this class. We can't have it separate from the DoublyLinkedList class, since we will need to access the Node class.

The solution to this is to put the DoublyLinkedListIterator class inside the DoublyLinkedList class, much like what we did with the Node class. This way, the Iterator has access to all private variables, methods, and classes within the DoublyLinkedList class.

public class DoublyLinkedListIterator {

	private Node head;
	private Node tail;

	private class Node {
	 	////******************
		/// *** Node class ***
		/// ******************
	}

	public class DoublyLinkedListIterator implements Iterator{
		//// **************************************
		//// ** DoublyLinkedListIterator Class ****
		//// **************************************
	}

	//// *************************
	//// ***** DLL methods *******
	//// *************************
	
	// A method that can be called to get a new Iterator
	public Iterator iterator() {
		return new DoublyLinkedListIterator();
	}
}

Now lets start writing the DoublyLinkedListIterator class itself. The Iterator should contain some sort of Index reference that it will use to traverse the list. So lets have a Node member variable called Index, and we'll initialize it to head when the constructor is called.

private Node index;

public DoublyLinkedListIterator(){
	index = head;
}

So, our Index reference will point to the node that we want to return by the next call to the next() method. So our next() method will store the data found in index, increment index, and then return the stored data. Also, we want to throw a NoSuchElementException if theres nothing left in the list.

public Object next() {
	if (index== null) throw new NoSuchElementException(); // throw an exception 
					//if there are no more elements left
	
	Object toReturn = index.getData();
	index = index.getNext();
	return toReturn;
	
}

Next, we'll write a hasNext() method. This method just needs to check wether or not index is null.

public boolean hasNext(){
	return (index!=null)
}

Finally, to satisfy the Interace, we need to have a remove(). However, all it does is immediately throw the UnsupportedOperationException.

public void remove(){
	throw new UnsupportedOperationException();
}

Now, we have a way to Iterate through the DoublyLinkedList. Whats even better, since our Iterator follows the interface, it works exactly the same as an Iterator for any other type of List. This means that a programmer doesn't even need to know what kind of List he is using to use the Iterator!

That about wraps up our coverage of LinkedLists. Next week, we'll start talking about new data structures such as Queues and Stacks.