April 19, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Working With Design Patterns: Iterator

  • July 9, 2008
  • By Jeff Langr
  • Send Email »
  • More Articles »

Iterator is a pattern? Come on, now! You've known how to step sequentially through a collection of objects since childhood. Programmer childhood, anyway.

Remember that the Design Patterns book, in which the iterator pattern was formally defined as part of a catalog of patterns, was published in 1995. No Java to speak of: C++ was the dominant OO language. Object-oriented development itself was new to most programmers.

C++ coders at the time typically would provide a custom mechanism to allow iteration against a collection. A programmer might provide prev and next methods to allow moving forward and backward through a linked list. For other collections, they might even expose a pointer to an encapsulated data structure, such as an array, and let the client figure out how to iterate it. In many cases, the solution for iteration involved exposing lots of specific details about the underlying collection implementation.

Smalltalk, also prevalent at the time, included a consistent set of internal iterators, afforded by its use of closures. An internal iterator controls the iteration across a collection, whereas an external iterator allows a client to control iteration. External iterators in general provide more flexibility, allowing the client to define particular iteration uses that the designers of the collection class might not have considered. In contrast, internal iterators simplify the work that client code must do.

Smalltalk programmers had it very easy. Faced with the need to iterate any kind of collection, they could always use one of the handful of standard iteration mechanisms (do:, select:, detect:, reject:, and inject:into:).

Java entered the scene with a minimal set of collection classes that supported external iteration. The original workhorse collection class Vector provided an elements() method that returned an Enumeration object. Clients could use this Enumeration object as the basis for iterating across a collection:

Vector names = new Vector();
names.add("Yossarian");
names.add("Minderbinder");
names.add("Clevinger");
for (Enumeration e = names.elements(); e.hasMoreElements(); ) {
   String name = (String)e.nextElement();
   // ...
}

Of course, the existence of this iteration mechanism didn't prevent programmers from bypassing it:

for (int i = 0; i < names.size(); i++) {
   String name = (String)names.get(i);
   // ...
}

Some developers to this day prefer this form of iteration, sometimes taking advantage of (possibly) slightly improved performance. But it's not as object-oriented, if that matters, because clients must understand the underlying representation of the list, never mind how simple it is in the case of Vector. If the programmer decides to change the collection to an unordered one (such as a set), the loop must be recoded.

With Java 2's collection class framework, Sun introduced a more robust set of collection classes that used a consistent set of interfaces and iterators. Enumeration was replaced with Iterator, and the method names simplified, to help make looping through a collection a bit more concise:

List names = new ArrayList();
names.add("Yossarian");
names.add("Minderbinder");
names.add("Clevinger");

for (Iterator it = names.iterator(); it.hasNext(); ) {
   String name = (String)it.next();
   // ...
}

Figure 1 shows a UML representation of the iterator pattern, as implemented in ArrayList from JDK 1.2 through JDK 1.4. Note that this is a simplified diagram, omitting some intermediary abstract classes and interfaces.

Figure 1: The iterator pattern.

Oddly, I still see Java programmers who choose to use Vector instead of ArrayList, and never mind that idea of assigning to an interface type, thank you but no thanks. If they claim an excuse other than "having a tough time kicking a ten-year-old habit," it might be that they want the synchronization that comes with Vector by default, although they could certainly use the synchronization wrappers in the collections framework. A more legitimate excuse I've heard is that they wanted control over the growth increment for Vector, something that disappeared with the newer ArrayList class.

Three different iteration techniques for traversing a list apparently was not enough. With Java 5, Sun introduced the enhanced-for loop, providing another mechanism for collection traversals:

List<String> names = new ArrayList<String>();
names.add("Yossarian");
names.add("Minderbinder");
names.add("Clevinger");

for (String name: names) {
   // ...
}




Page 1 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel