Section 11.1. Iterable and Iterators


11.1. Iterable and Iterators

An iterator is an object that implements the interface Iterator:

 public Iterator<E> {   boolean hasNext();   // return true if the iteration has more elements       E next();            // return the next element in the iteration   void remove();       // remove the last element returned by the iterator } 

The purpose of iterators is to provide a uniform way of accessing collection elements sequentially, so whatever kind of collection you are dealing with, and however it is implemented, you always know how to process its elements in turn. This used to require some rather clumsy code; for example, in earlier versions of Java, you would write the following to print the string representation of a collection's contents:

 // coll refers to an object which implements Collection // ----- not the preferred idiom from Java 5 on ------- for (Iterator itr = coll.iterator() ; itr.hasNext() ; ) {   System.out.println(itr.next()); } 

The strange-looking for statement was the preferred idiom before Java 5 because, by restricting the scope of itr to the body of the loop, it eliminated accidental uses of it elsewhere. This code worked because any class implementing Collection has an iterator method which returns an iterator appropriate to objects of that class. It is no longer the approved idiom because Java 5 introduced something better: the foreach statement, which you met in Part I. Using foreach, we can write the preceding code more concisely:

 for (Object o : coll) {   System.out.println(o); } 

This code will work with anything that implements the interface Iterablethat is, anything that can produce an Iterator. This is the declaration of Iterable:

 public Iterable<T> {   Iterator<T> iterator();   // return an iterator over elements of type T } 

In Java 5 the Collection interface was made to extend Iterable, so any set, list, or queue can be the target of foreach, as can arrays. If you write your own implementation of Iterable, that too can be used with foreach. Example 11.1 shows just about the simplest possible example of how Iterable can be directly implemented. A Counter object is initialized with a count of Integer objects; its iterator returns these in ascending order in response to calls of next().

Directly implementing Iterable

 class Counter implements Iterable<Integer> {   private int count;   public Counter(int count) { this.count = count; }   public Iterator<Integer> iterator() {     return new Iterator<Integer>() {       private int i = 0;       public boolean hasNext() { return i < count; }       public Integer next() { i++; return i; }       public void remove(){ throw new UnsupportedOperationException(); }     };   } } 

Now Counter objects can be the target of a foreach statement:

 int total = 0; for (int i : new Counter(3)) {    total += i; } assert total == 6; 

In practice, it is unusual to implement Iterable directly in this way, as foreach is most commonly used with arrays and the standard collections classes.

The iterators of the general-purpose collections in the FrameworkArrayList, HashMap, and so oncan puzzle novice users by throwing ConcurrentModificationException from single-threaded code. These iterators throw this exception whenever they detect that the collection from which they were derived has been structurally changed (broadly speaking, that elements have been added or removed). The motivation for this behavior is that the iterators are implemented as a view of their underlying collection so, if that collection is structurally changed, the iterator may well not be able to continue operating correctly when it reaches the changed part of the collection. Instead of allowing the manifestation of failure to be delayed, making diagnosis difficult, the general-purpose Collections Framework iterators are fail-fast. The methods of a fail-fast iterator check that the underlying collection has not been structurally changed (by another iterator, or by the methods of the collection itself) since the last iterator method call. If they detect a change, they throw ConcurrentModificationException. Although this restriction rules out some sound programs, it rules out many more unsound ones.

The concurrent collections have other strategies for handling concurrent modification, such as weakly consistent iterators. We discuss them in more detail in Section 11.5.




Java Generics and Collections
Java Generics and Collections
ISBN: 0596527756
EAN: 2147483647
Year: 2006
Pages: 136

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net