0% found this document useful (0 votes)
49 views32 pages

CSE 12 Implementing The Iterator Pattern

This document discusses implementing the Iterator pattern in Java. It covers the Iterator interface, how to define classes that implement Iterator, and how to use iterators to iterate over collections without knowing their internal structure. It provides an example of an iterator for a singly linked list, with partial code showing how to track the next, last returned, and predecessor nodes to support the iterator methods. The document is aimed at teaching how to properly implement iterators over user-defined collection classes in Java.

Uploaded by

ShengFeng
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
49 views32 pages

CSE 12 Implementing The Iterator Pattern

This document discusses implementing the Iterator pattern in Java. It covers the Iterator interface, how to define classes that implement Iterator, and how to use iterators to iterate over collections without knowing their internal structure. It provides an example of an iterator for a singly linked list, with partial code showing how to track the next, last returned, and predecessor nodes to support the iterator methods. The document is aimed at teaching how to properly implement iterators over user-defined collection classes in Java.

Uploaded by

ShengFeng
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 32

CSE 12

Implementing the Iterator Pattern


The Collection and Iterable interfaces
The Iterator Design Pattern
The Iterator interface
Defining classes that implement the Iterator interface
The concurrent modification problem

07

The Iterator Software Design Pattern


A common situation: A client needs to inspect the data
elements in a collection, without wanting to know details of how
the collection structures its data internally
Solution:
Define an interface that specifies how an iterator will behave
Define an interface that every collection must implement,
which specifies how to obtain from the collection an object
that implements that iterator interface

A client then can ask the collection for an iterator object,


and use that iterator to inspect the collections elements,
without having to know how the collection is implemented

4-2/36

Using a Java Iterator

A typical use of an Iterator for a


might be something like:

Collection<String> c

Iterator<String> i = c.iterator();
while ( i.hasNext() ) {
String x = i.next(); // get the next String in c
if ( x.length() > 10 ) { // and do something with it
System.out.println(x + is longer than 10 chars);
}
}

(Here, c is referred to as the backing collection of the


Iterator i)
07-3/23

Using iterators

Since Java 5, a new foreach style syntax is


available to even more conveniently write an
iteration over the elements of any object (such as a
Collection) that implements the Iterable interface.

Again, suppose that c is a Collection<String> :


for( String x: c ) {
if ( x.length() > 10 ) {
System.out.println(x + is longer than 10 chars);
}
}

07-4/23

Java Collections Framework (JCF)


The JCF is a collection of interfaces, abstract and concrete
classes providing a standard set of collection (container)
types.
The Collection interface is considered to be the root of
the JCF interface inheritance hierarchy
However Collection itself extends the Iterable
interface

Iterable<E> Interface
The Collection<E> interface extends the
Iterable<E> interface, which is defined as follows:

public interface Iterable<E> {


public Iterator<E> iterator();
}
So any class that implements Collection<E> must
define an instance method iterator() that returns an
Iterator<E> object for that instance

What is Iterator<E>? It is also an interface in the JCF

4-6/36

Collection<E> Required methods


boolean contains(Object target)

Returns true if this collection contains the target


element.

boolean containsAll(Collection<?> c)

Returns true if this collection contains all of the


elements in the collection c.

boolean isEmpty()

Returns true if this collection contains no


elements.

int size()

Returns the number of elements stored in this


collection.

Iterator<E> iterator()

Returns an iterator over the elements in this


collection. (Inherited from Iterable<E>.)

Object[] toArray()

Returns an array containing all of the elements in this


collection.

<T> T[] toArray(T[] a)

Returns an array containing all of the elements in this


collection with runtime type T.

Iterator<E> Interface

The Iterator<E> interface is defined as follows:


public interface Iterator<E> {
public E next();
public boolean hasNext();

public void remove();


}

So, any object that is-a Iterator<E> will have those


operations as part of its API.

But what are these methods supposed to do, exactly?...


4-8/36

Iterator<E> method descriptions


boolean hasNext()

Returns: true if the iteration has more elements. (In other


words, returns true if next would return an element rather
than throwing an exception.)
E next()
Returns: the next element in the iteration.

Throws:
NoSuchElementException - if iteration has no more
elements.

4-9/36

Iterator<E> method descriptions, contd


void remove()
Removes from the underlying collection the last element
returned by the iterator (optional operation).
This method can be called only once per call to next().
The behavior of an iterator is unspecified if the underlying
collection is modified while the iteration is in progress in
any way other than by calling this method.
Throws:
UnsupportedOperationException - if
the remove operation is not supported by this Iterator.
IllegalStateException - if the next method has not yet
been called, or the remove method has already been
called after the last call to the next method.
4-10/36

Implementing an Iterator class

Understanding what an Iterator object is supposed to


do is the first step

Now let's look at some strategies for implementing an


Iterator class (i.e. a class that implements the
java.util.Iterator<E> interface)

Two approaches to consider:


define a class separate from your collection class
define an inner class in your collection class

A separate Iterator class

Suppose you have declared a generic class Foo to


implement a Collection interface

In outline, the class definition for an Iterator to be


returned from a Foo objects iterator() method might be:
public class FooIterator<T> implements java.util.Iterator<T> {
private Foo<T> c; // pointer to the backing Collection
FooIterator(Foo<T> x) { c = x; /* and other initlzation */ }
public boolean hasNext() { /* see if any elts remain */ }
public T next() { /* return next elt, or throw if none*/ }
public void remove() { /* remove the last elt returned */ }

// any other needed instance variables, helper methods...


}

07-12/23

A separate Iterator class

The instance methods of a separate class like this have


access only to the public (and package, if in the same
package) instance variables and methods of the
backing Collection object; if this isnt enough access to
do what it needs to do, its a problem!

But with enough access, the iterator() method of the


backing Foo class can now be quite simple. It just
creates an instance of the FooIterator class and
returns a pointer to it:
public java.util.Iterator<E> iterator() {
return new FooIterator<E>(this);

07-13/23

An inner Iterator class

In Java, an easier and more flexible way to define an


Iterator class for a class that implements Collection<E>
is to define an instance (i.e., not static) private inner
class, within the body of the definition of the class that
implements Collection<E>

In outline, the inner class definition would look like:


private class LLIter implements java.util.Iterator<E> {
LLIter() { /* initlize an instance of this inner class */ }
public boolean hasNext() { /* see if any elts remain */}
public E next() {/* return next elt, or throw if none*/}
public void remove() { /* remove the last elt returned */}
// any needed separate instance variables for the Iterator
}

07-14/23

An inner Iterator class

The instance methods of a (nonstatic) inner class like


that have access to all the instance variables and
methods of its enclosing class, so the Iterator can
easily do everything it needs to do

Then the iterator() method of the backing Collection can


be very simple. It just creates an instance of the inner
class, and returns a pointer to it:
public java.util.Iterator<E> iterator() {
return new LLIter();
}

Implementing the Iterator methods

The Iterator needs to do these things efficiently:

find the first element in the backing structure, to


initialize the Iterator

find the next element that has not yet been visited
in the backing structure, and...

visit it (i.e., return a pointer to the data stored


there)

tell whether or not there is a next element that has


not been visited

remove the most-recently visited element from the


backing structure

Lets look at how these can be realized for a simple


linked-list backing structure

A simple linked list class...

Suppose a linked list class is defined (in part) like this:

public class SinglyLinkedList<E> implements java.util.List<E> {


private static class Node<T> { // private static inner class
Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
T data;
Node<T> next;
}

private Node<E> header;

// pointer to dummy header node

public LinkedList() {
header = new Node<E>(null,null); // create the dummy node
}
// etc...

An iterator for a singly-linked list

Finding the first element in an instance of that singly-linked list is


easy: its what header.next is pointing to, if header.next is not
null

Finding the next element to visit is easy: just follow the next
pointer from the last element visited (if that pointer is null, there is
no next element)

Deleting the last element visited requires more thought: you need
to keep a pointer to the predecessor of the last element visited

If we implement the Iterator interface as an instance (i.e.


nonstatic) inner class, its instance methods can access everything
about its backing structure (the enclosing LinkedList instance)

Then all this can be accomplished with 3 instance variables in the


Iterator, and defining the Iterators instance methods
accordingly... partial example next

A partial implementation...
private class LLIter implements java.util.Iterator<E> {
private Node<E> next; // the Node next to be visited
private Node<E> lastReturned; // the Node last visited
private Node<E> pred; // the predecessor of lastReturned

LLIter() { next = header.next; /* initialize... */ }


public boolean hasNext() { return next != null; }
public E next() {
if (next == null) throw new NoSuchElementException();
lastReturned = next;
/* update next and pred pointers... */
return lastReturned.data;
}

public void remove() {


if(lastReturned == null) throw new IllegalStateException();
/* splice around lastReturned... */
lastReturned = null;
}

About that partial implementation


We chose LLIter as the name of that inner class, but it
could be any name
The type parameter E was introduced in the outer class,
not the inner class; this inner class just uses that parameter

The outer class instance variable header is accessible in


this inner class, because it is a nonstatic, instance inner
class (see the definition of its constructor) .
This access is the reason to use an instance inner class!

A linked list picture

Create a LinkedList object, and add some elements


LinkedList<Integer> x = new LinkedList<Integer>();

x.add(15); x.add(10); x.add(40); x.add(77);

header

next
data

next
data

next
data
15

next
data
10

next
data
40

77

Now let's create an Iterator for that LinkedList, and use it

An linked list iterator picture


it

Iterator<Integer> it = x.iterator();
System.out.print(it.next());
System.out.print(it.next());

pred

lastRet

next

it.remove();
System.out.print(it.next());
System.out.print(it.hasNext());

header

next
data

next
data

next
data
15

next
data
10

next
data
40

77

Issue: Concurrent modification


What happens if the backing collection is modified while an
iteration is in progress? This could be a problem!
This issue is called concurrent modification and occurs
when the collection is structurally modified through the
collection object or another Iterator while an iteration is in
progress. Some scenarios:

An element is added to the collection and is placed just


before the Iterator's current position, so will be missed
by the Iterator

The element at the Iterator's current position is


removed, but the Iterator will return it with next()

If a concurrent modification has occurred, any Iterator method


should throw a ConcurrentModificationException

Concurrent modification: an approach


Problem: How to detect concurrent modification

Solution: add a modcount variable to the backing collection


class to keep track of structural modifications (adds/deletes)
modcount is incremented each time the collection object
is structurally modified via an add or remove operation
from Collection
When a Iterator object is created, it copies the
collections modCount variable into a local variable,
expectedModCount
The iterator methods check for concurrent modification by
seeing if expectedModCount is equal to modCount. If
there have been no structural changes to the collection,
the two count variables will be equal, otherwise an
exception is thrown

Dealing with Concurrent Modification


Collection
modCount

Iterator
expectedModCount

Collection<String> c = new
LinkedList<String>()

c.add(A)

c.add(B)

Iterator<String> iter = c.iterator()

iter.next()

iter.remove()

c.remove()

operation

iter.next()

throw ConcurrentModificationException

Using an abstract class in the JCF


The JCF provides several abstract classes to make
implementation of JCF interfaces easier
For example, the AbstractList abstract class has only 5
abstract methods:
abstract
abstract
abstract
abstract
abstract

public
public
public
public
public

void add(int index, E element);


E get(int index);
E remove(int index);
E set(int index, E element);
int size();

AbstractList defines all other required List methods in terms


of these
So you just need to define a class that extends AbstractList,
and define those 5 methods in it, and your class will be a
complete implementation of List

AbstractLists implementation of iterator()


The implementation of the iterator() method in AbstractList:
public Iterator<E> iterator() {
return new Itr();
}

Itr is a private nonstatic inner class of AbstractList

Class Itr
private class Itr implements Iterator<E> {
/** Index of element to be returned by subsequent call to next. */
int cursor = 0;
/** Index of element returned by most recent call to next or
*

previous.

to remove.

Reset to -1 if this element is deleted by a call

*/

int lastRet = -1;


/** The modCount value that the iterator believes that the backing
* List should have.
*

If this expectation is violated, the iterator

has detected concurrent modification.

int expectedModCount = modCount;

*/

Class Itr, continued


public boolean hasNext() {
return cursor != size();
}
public E next() {
checkForComodification();
try {

int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}

Class Itr, continued


public void remove() {
if (lastRet < 0) throw new IllegalStateException();
checkForComodification();
try {
remove(lastRet);
cursor--;

lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)

throw new ConcurrentModificationException();


}
}

AbstractLists implementation of iterator()


The Iterator returned by AbstractLists iterator() method is
correct: it meets the specification of the Iterator interface
However, it is not efficient, when the backing store is a linked
list. Suppose the list contains N elements:
The next() method of the iterator uses the get(int) method
of the outer class, which is O(N) worst case
The remove() method of the iterator uses the remove(int)
method of the outer class, which is O(N) worst case
The approach shown previously is O(1) for both of those
operations, and so it would be better!

Next time

The Stack ADT


Designing a test plan for Stack
The Adapter design pattern
Alternative implementations of Stack
Time costs of Stack implementations

Reading: Gray, Ch 6

You might also like