Collections - Iterators and Enumeration

Difference between Iterator and Enumeration in Java

Sr. No. Key Iterator Enumeration
1. Basic In Iterator, we can read and remove element while traversing element in the collections. Using Enumeration, we can only read element during traversing element in the collections.
2. Access It can be used with any class of the collection framework. It can be used only with legacy class of the collection framework such as a Vector and HashTable.
3. Fail-Fast and Fail -Safe Any changes in the collection, such as removing element from the collection during a thread is iterating collection then it throw concurrent modification exception. Enumeration is Fail safe in nature. It doesn’t throw concurrent modification exception
4. Limitation Only forward direction iterating is possible Remove operations can not be performed using Enumeration.
5. Methods It has following methods − *hasNext() *next() *remove() It has following methods − *hasMoreElements() *nextElement()

Alternate:

Iterator Enumeration
Iterator is a universal cursor as it is applicable for all the collection classes. Enumeration is not a universal cursor as it applies only to legacy classes.
Iterator has the remove() method. Enumeration does not have the remove() method.
Iterator can do modifications (e.g using remove() method it removes the element from the Collection during traversal). Enumeration interface acts as a read only interface, one can not do any modifications to Collection while traversing the elements of the Collection.
Iterator is not a legacy interface. Iterator can be used for the traversal of HashMap, LinkedList, ArrayList, HashSet, TreeMap, TreeSet. Enumeration is a legacy interface which is used for traversing Vector, Hashtable.

Iterator and Enumeration both are the cursors to traverse and access an element from the collection. They both belong to the collection framework. Enumeration was added in JDK1.0 and Iterator in the JDK.1.2 version in the collection framework.

Enumeration can’t make structural changes in the collection because it has read-only access to the element in the collection. It has the following methods :

  1. hasMoreElements()
  2. nextElement()

On the other hand, an iterator can read and remove the element in the collection. It has the following methods −

  1. hasNext()
  2. next()
  3. remove()

Enumerations

https://docs.oracle.com/javase/7/docs/api/java/util/Enumeration.html

package com.my.company.datastructures.hashtables;

import java.util.Enumeration;
import java.util.Hashtable;

public class IteratingAHashTable {

    public static void main(String args[]) {
        Hashtable<Integer, String> ht1 = new Hashtable<>();

        Hashtable<Integer, String> ht2 = new Hashtable<Integer, String>();

        ht1.put(1, "one");
        ht1.put(2, "two");
        ht1.put(3, "three");

        ht2.put(4, "four");
        ht2.put(5, "five");
        ht2.put(6, "six");

        System.out.println("Mappings of ht1 : " + ht1);
        System.out.println("Mappings of ht2 : " + ht2);

        // Iterating through the values of the HashTable using Enumeration
        Enumeration<String> e = ht1.elements();
        while (e.hasMoreElements())
        {
            String currentValue = e.nextElement();
            System.out.println("currentValue: " + currentValue);
        }
    }
}

Iteration

Reference : Algorithhms by Robert Sedgewick, Kevin Wayne

One of the fundamental operations on collections is to process each item by iterating through the collection using Java’s foreach statement. This paradigm leads to clear and compact code that is free from dependence on the details of a collection’s implementation. To consider the task of implementing iteration, we start with a snippet of client code that prints all of the items in a collection of strings, one per line:

Stack<String> collection = new Stack<String>();
...
for (String s : collection)
StdOut.println(s);
...

Now, this foreach statement is shorthand for a while construct (just like the for statement itself). It is essentially equivalent to the following while statement:

Iterator<String> i = collection.iterator();
while (i.hasNext())
{
        String s = i.next();
        StdOut.println(s);
}

This code exposes the ingredients that we need to implement in any iterable collection:

  1. The collection must implement an iterator() method that returns an Iterator object.
  2. The Iterator class must include two methods: hasNext() (which returns a boolean value) and next() (which returns a generic item from the collection).

In Java, we use the interface mechanism to express the idea that a class implements a specific method. For iterable collections, the necessary interfaces are already defined for us in Java. To make a class iterable, the first step is to add the phrase implements Iterable<Item> to its declaration, matching the interface

public interface Iterable<Item>
{
        Iterator<Item> iterator();
}

(which is in java.lang.Iterable), and to add a method iterator() to the class that returns an Iterator<Item>. Iterators are generic, so we can use our parameterized type Item to allow clients to iterate through objects of whatever type is provided by our client. For the array representation that we have been using, we need to iterate through an array in reverse order, so we name the iterator ReverseArrayIterator and add this method:

public Iterator<Item> iterator()
{
        return new ReverseArrayIterator();
}

What is an iterator?

An object from a class that implements the methods hasNext() and next(), as defined in the following interface (which is in java.util.Iterator ):

public interface Iterator<Item>
{
        boolean hasNext();
        Item next();
        void remove();
}

Although the interface specifies a remove() method, we always use an empty method for remove() in this book, because interleaving iteration with operations that modify the data structure is best avoided. For ReverseArrayIterator, these methods are all one-liners, implemented in a nested class within our stack class:

private class ReverseArrayIterator implements Iterator<Item>
{
        private int i = N;

        public boolean hasNext()
        {
                return i > 0;
        }

        public Item next()
        {
                return a[--i];
        }

        public void remove()
        {

        }
}

Note that this nested class can access the instance variables of the enclosing class, in this case a[] and N (this ability is the main reason we use nested classes for iterators). Technically, to conform to the Iterator specification, we should throw exceptions in two cases:

  1. an UnsupportedOperationException if a client calls remove() and a NoSuchElementException if a client calls next() when i is 0 .
  2. Since we only use iterators in the foreach construction where these conditions do not arise, we omit this code.

One crucial detail remains: we have to include import java.util.Iterator; at the beginning of the program because (for historical reasons) Iterator is not part of java.lang (even though Iterable is part of java.lang). Now a client using the foreach statement for this class will get behavior equivalent to the common for loop for arrays, but does not need to be aware of the array representation (an implementation detail). This arrangement is of critical importance for implementations of fundamental data types like the collections that we consider in this book and those included in Java libraries. For example, it frees us to switch to a totally different representation without having to change any client code. More important, taking the client’s point of view, it allows clients to use iteration without having to know any details of the class implementation.

TODO See ResizingArrayStack.java - ReverseArrayIterator

iterator interface

  1. The Iterator interface is used to step through the elements of a Collection.
  2. Iterators let you process each element of a Collection.
  3. Iterators are a generic way to go through all the elements of a Collection no matter how it is organized.
  4. Iterator is an Interface that is implemented in a different way for every Collection.

To use an iterator to traverse through the contents of a collection, follow these steps:

  1. Obtain an iterator to the start of the collection by calling the collections’ iterator() method.
  2. Set up a loop that makes a call to hasNext(). Have the loop iterate as long as hasNext() returns true.
  3. Within the loop, obtain each element by calling next().

remove elements during Iteration

Iterator also has a method remove(). When remove() is called, the current element in the iteration is deleted.

Iterator iter=Collection.iterator();
while(iter.hasNext()){
    Object o=iter.next()
    if(o.equals(what i'm looking for)){
        iter.remove();
    }
}

ListIterator

ListIterator is just like Iterator, except it allows us to access the collection in either the forward or backward direction and lets us modify an element.

How do they work in modern and legacy applications?

Adapter pattern

Look at the example showing how they work together here:

https://github.com/explorer436/programming-playground/tree/main/java-playground/design-pattern-samples/design-pattern-examples/src/main/java/com/my/company/adapterpattern