Recap: how to make our linked list iterable

  • In order to use our linked list with a for-each-loop:

          GenericLinkedList stringList = new GenericLinkedList();
    
          stringList.addFirst("C");
          stringList.addFirst("B");
          stringList.addFirst("A");
    
          // Use our linked list in a for-each loop
          for ( String s : stringList )
              System.out.println(s);
    

    our GenericLinkedList class must implement the Iterable<T>:

       // Implementing this interface allows an object to be 
       // the target of the "for-each loop" statement. 
    
       public interface Iterable<T>
       {
           public Iterator<T> iterator();
            // Returns an iterator (object) over elements of type T.
       }

    Documentation on Iterable:

Recap: how to make our linked list iterable

  • To implement the Iterable<T> interface, our GenericLinkedList<T> must define all the methods in the Iterable<T> interface:

    public class GenericLinkedList<T> implements SimpleList<T>, Iterable<T>
    {
       private class Node<T>
       {
          private T item;
          private Node<T> next;
    
          ...
       }
    
       private Node<T> first;   // Start of linked list
    
       public GenericLinkedList()
       {
          first = null;
       }
    
       ....
    
       public Iterator<T> iterator() // Implements the Iterable<T> interface 
       {
           // Returns an iterator (object) over elements of type T.
           // We must define a class that returns an Iterator<T> object
       }  
    }
    

Defining a class used to create an Iterator object

  • The Iterator<T> interface of Java:

       public interface Iterator<T>
       {
           public boolean hasNext(); 
                    // Returns true if the iteration has more elements.
     
           public T next(); 
                    // Returns the next element in the iteration.
       }
    

  • A class that can be used to create an Iterator<T> must implement the interface, e.g.:

      public class MyLinkedListIterator<T> implements Iterator<T>
      {
          // *** what variables do we need to implement this object ? ***
    
          public boolean hasNext()
          { 
             // Returns true if the iteration has more elements.
          }
     
          public T next()
          {
              // Returns the next element in the iteration.
          }
      }
    

Iterating over a linked list

  • Iterating over a linked list is visiting every node in the linked list:

  • This is done using the list traversal algorithm:

       Node current = first;
    
       while ( current != null ) // Find last list element
       {
           // Process current node here
    
           current = current.next;  // Move to next node
       }
    
    

  • The MyLinkedListIterator<T> class must implement the steps of the list traversal algorithm !!!

Defining a class used to create an Iterator object

Let's write the MyLinkedListIterator<T> class:    (comment: we are not making a linked list, but an iterator)

  public class MyLinkedListIterator<T> implements Iterator<T>
  {
      // *** what variables do we need to implement this object ? ***
    
      public MyLinkedListIterator(???) // Constructor (every class needs one)
      {
         // Initialize variables !
      }

      public boolean hasNext() // Returns true if there are more elements.
      {
         return current != null; // we aren't at the last node    
      }

      public T next() // Returns the next element in the iteration.
      {
         if ( ! hasNext() )
            throw new NoSuchElementException();

         T res = current.item;    // get item at current position
         current = current.next; // move to the next node
         return res;
      }
  }

Defining a class used to create an Iterator object

The Iterator object must remember the current node in the linked list: we use current for this purpose

  public class MyLinkedListIterator<T> implements Iterator<T>
  {
      private Node <T> current;  // Current position in the iteration
    
      public MyLinkedListIterator(???) // Constructor (every class needs one)
      {
         // Initialize variables !
      }

      public boolean hasNext() // Returns true if there are more elements.
      { 
         return current != null; // we aren't at the last node    
      }

      public T next() // Returns the next element in the iteration.
      {
         if ( ! hasNext() )
            throw new NoSuchElementException();

         T res = current.item;    // get item at current position
         current = current.next; // move to the next node
         return res;
      }
  }

Defining a class used to create an Iterator object

The constructor is used to initiates current (we will pass first to the constructor):

  public class MyLinkedListIterator<T> implements Iterator<T>
  {
      private Node <T> current;  // Current position in the iteration
    
      public MyLinkedListIterator(Node<T> f) // Constructor (every class needs one)
      {
          current = f;  // Initialize   
      }

      public boolean hasNext() // Returns true if there are more elements.
      { 
         return current != null; // we aren't at the last node    
      }

      public T next() // Returns the next element in the iteration.
      {
         if ( ! hasNext() )
            throw new NoSuchElementException();

         T res = current.item;    // get item at current position
         current = current.next; // move to the next node
         return res;
      }
  }

Defining a class used to create an Iterator object

The hasNext() method returns true if current == null and false otherwise:

  public class MyLinkedListIterator<T> implements Iterator<T>
  {
      private Node <T> current;  // Current position in the iteration
    
      public MyLinkedListIterator(Node<T> f) // Constructor (every class needs one)
      {
          current = f;  // Initialize   
      }

      public boolean hasNext() // Returns true if there are more elements.
      { 
         return current != null;  // True if there are unvisited nodes 
      }

      public T next() // Returns the next element in the iteration.
      {
         if ( ! hasNext() )
            throw new NoSuchElementException();

         T res = current.item;    // get item at current position
         current = current.next; // move to the next node
         return res;
      }
  }

Defining a class used to create an Iterator object

The next() method returns the item in the current node and advance the current pointer:

  public class MyLinkedListIterator<T> implements Iterator<T>
  {
      private Node <T> current;  // Current position in the iteration
    
      public MyLinkedListIterator(Node<T> f) // Constructor (every class needs one)
      {
          current = f;  // Initialize   
      }

      public boolean hasNext() // Returns true if there are more elements.
      { 
         return current != null;  // True if there are unvisited nodes 
      }

      public T next() // Returns the next element in the iteration.
      {
         if ( ! hasNext() )
            throw new NoSuchElementException();

         T res = current.item;    // get item at current position
         current = current.next; // move to the next node
         return res;
      }
  }

Defining a class used to create an Iterator object

The next() method must throw an exception when there are no more elements left: (and we are done)

  public class MyLinkedListIterator<T> implements Iterator<T>
  {
      private Node <T> current;  // Current position in the iteration
    
      public MyLinkedListIterator(Node<T> f) // Constructor (every class needs one)
      {
          current = f;  // Initialize   
      }

      public boolean hasNext() // Returns true if there are more elements.
      { 
         return current != null;  // True if there are unvisited nodes 
      }

      public T next() // Returns the next element in the iteration.
      {
         if ( ! hasNext() )
            throw new NoSuchElementException();

         T res = current.item;    // get item at current position
         current = current.next; // move to the next node
         return res;
      }
  }

Recall: how to make our linked list iterable

  • After we have defined a class to make an Iterator<T> object, we can now finish the iterator() method:

    public class GenericLinkedList<T> implements SimpleList<T>, Iterable<T>
    {
       private class Node<T>
       {
          private T item;
          private Node<T> next;
    
          ...
       }
    
       private Node<T> first;   // Start of linked list
    
       public GenericLinkedList()
       {
          first = null;
       }
    
       ....
    
       public Iterator<T> iterator() // Implements the Iterable<T> interface 
       {
           // ??? Returns an iterator (object) over elements of type T. Quiz
           // Use MyLinkedListIterator<T> to make an Iterator<T> object
       }  
    }
    

Recall: how to make our linked list iterable

  • The iterator() method returns a MyLinkedListIterator<T> object initialized using the first node of the linked list first:

    public class GenericLinkedList<T> implements SimpleList<T>, Iterable<T>
    {
       private class Node<T>
       {
          private T item;
          private Node<T> next;
    
          ...
       }
    
       private Node<T> first;   // Start of linked list
    
       public GenericLinkedList()
       {
          first = null;
       }
    
       ....
    
       public Iterator<T> iterator() // Implements the Iterable<T> interface 
       {
           return new MyLinkedListIterator<T>( first );
           // Use MyLinkedListIterator<T> to make an Iterator<T> object
       }  
    }
    

Organizing the MyLinkedListIterator<T> class

  • Recall we wrote the Node<T> class as an inner class of the GenericLinkedList<T> class:
     

    public class GenericLinkedList<T> implements SimpleList<T>
    {
       /*******************************************************
         The private inner class "Node"
        *******************************************************/
       private class Node<T>
       {
          private T item;
          private Node<T> next;
    
          public Node(T item, Node<T> next)
          {
             this.item = item;
             this.next = next;
          }
    
          public String toString(){ return "" + this.item; }
       } // End of private inner class "Node"
    
       ...
    }
    

    because Node<T> will only be used by methods inside the GenericLinkedList<T> class

Organizing the MyLinkedListIterator<T> class

  • Similarly, the MyLinkedListIterator<T> class will only be used by methods inside the GenericLinkedList<T> class, so we make it into an inner class also:

    public class GenericLinkedList<T> implements SimpleList<T>, Iterable<T>
    {
       ....
       /*******************************************************
       * Private inner (nested) class MyLinkedListIterator
       * that implements the Java interface "Iterator"
       ********************************************************/
       private class MyLinkedListIterator<T> implements Iterator<T>
       {
           private Node <T> current;  // Current position in the iteration
         
           public MyLinkedListIterator(Node<T> f) // Constructor (every class needs one)
           {
     	   current = f;  // Initialize   
           }
        
           public boolean hasNext() // Returns true if there are more elements.
           { 
     	  return current != null;  // True if there are unvisited nodes 
           }
        
           public T next() // Returns the next element in the iteration.
           {
     	  if ( ! hasNext() )
     	     throw new NoSuchElementException();
        
     	  T res = current.item;    // get item at current position
     	  current = current.next; // move to the next node
     	  return res;
           }
       }
    }
    

SHOW: demo/11-linked-list/07-iterable-list/GenericLinkedList.java

Testing the iterable linked list

  • The following test program shows that we can now use our GenericLinkedList<T> class in a for-each-loop:

       public static void main(String[] args)
       {
          System.out.println("Iterator");
    
          GenericLinkedList<String> stringList =
                                    new GenericLinkedList<String>();
    
          stringList.addFirst("C");
          stringList.addFirst("B");
          stringList.addFirst("A");
          System.out.println(stringList); // A -> B -> C
    
          for ( String s : stringList )
              System.out.println(s);
       }

DEMO: demo/11-linked-list/08-iterable-list/Demo.java

Postscript: re-writing a for-each-loop into a while-loop

  • A for-each-loop can always be re-written as a while-loop

    • You can see the Iterator methods in a while-loop...



  • When you write the following for-each-loop:

       for ( dataType x : X )  // X is an iterable object
       {
           ...
       }
    

    The Java compiler will translate it into this program code:

       Iterator<dataType> helpIter = X.iterator(); 
    
       while ( helpIter.hasNext() )
       {
           dataType x = helpIter.next();
           ....
       }
    

Testing the iterable linked list with a while-loop

  • The following test program shows how to iterate over the GenericLinkedList<T> class with a while-loop:

       public static void main(String[] args)
       {
          System.out.println("Iterator");
    
          GenericLinkedList<String> stringList =
                                    new GenericLinkedList<String>();
    
          stringList.addFirst("C");
          stringList.addFirst("B");
          stringList.addFirst("A");
          System.out.println(stringList); // A -> B -> C
    
          Iterator<String> itr = stringList.iterator();
    
          while(itr.hasNext())
          {
              System.out.println(itr.next());
          }
    
       }

DEMO: demo/11-linked-list/08-iterable-list/Demo2.java