SlideShare a Scribd company logo
44 Java™
Report | OCTOBER 2001 http://www.javareport.com
T
HE CONTROL-FLOW structures of Java have
remained fairly stable since their arrival in C three
decades ago. They express the core structured-
programming primitives of sequential, selective, and
repetitive execution, as well as discontinuous control
flow, such as breaking from a loop. Selective execution
is much as it used to be, except it has lost some ground
to the use of polymorphism. The basic refinement to
sequential execution has been its disruption through
exceptions and its multiplication through threading,
both of which are supported in the heart of the language.
My previous two columns1, 2 explored patterns that cap-
tured differences in practice between single-threaded
and multi-threaded programming, and exception-free
and exception-throwing code.
Iteration constructs have changed little since days of
yore, but the subject of iteration has been objectified and
pattern-enriched with collections and iterators. To begin
at the beginning, there are five features that define any
iteration:
• The initialization to start the loop.
• The continuation condition to keep it running (or termi-
nation condition to stop it, depending on whether you
regard the glass as half-full or half-empty).
• The body of the loop to do the work.
• The advancement of the iteration to go around again.
This may be a distinct action, i.e., an increment, or a side
effect of something in the body of the loop.
• The finalization to clean up after the loop. This feature is
often optional, a no-op.
It is no coincidence that the four mandatory parts of a
loop correspond to the anatomy of the for.
The ITERATOR pattern3 represents what many OO devel-
opers think of as the design for iteration in an object sys-
tem, but there is more to iteration abstraction than just
ITERATOR. The rest of this column looks at three iteration
patterns whose solutions differ in their response to thread-
ing, distribution, exceptions, and parameterization. So
let’s start by looking in detail at something that should be
fairly familiar.
Iteration Pattern 1: ITERATOR
Support iteration over an encapsulated collection by plac-
ing responsibility for iteration into a separate object.
Problem. How can elements
of a collection be accessed
conveniently, sequentially, and
efficiently without exposing
its underlying representation
or making it less cohesive?
If the representation of a
collection is accessible, users
can access the internal struc-
ture of the object directly so
they can iterate over it.
However, users can under-
mine its structure, intention-
ally or otherwise, giving rise
to subtle bugs or assumptions
about undocumented class
behavior. Their code is also strongly coupled to the imple-
mentation details of the collection, so any changes to the
data structure will inevitably break the client code, and
any change of collection type will inevitably cause a
rewrite. It is not possible to work reasonably through an
interface if the implementation of a collection must be
known in order to use it.
It is tempting to use a conventional integer index to
look up elements. However, this is an abstraction too far,
hiding potentially expensive operations behind an inno-
cent-looking interface. To loop over every element in an
array-based sequence with an index is a linear-time oper-
ation (O(N) in O-notation), with the generated code visit-
ing each element precisely once in constant time. To do
the same for a linked-list implementation is significantly
more expensive (a pricey O(N2)) as previously visited
links in the list are retraversed each time to find the next
indexed element. To get a feel for what this means in
practice, an array of 10 elements will require 10 accesses,
whereas a list of 10 will require 55 link traversals. But
where an array of 100,000 elements requires 100,000
accesses, a list of the same length requires more than 5
billion link traversals. Hiding such a profound difference
between a random-access structure and a sequential-
access structure behind a weakly specified get interface
(no non-functional guarantees or warnings are given) is
questionable design.
In sequential-access cases, it can be more effective to
make use of a toArray method to get a snapshot of all the
elements and iterate over the returned array instead.
However, this still requires the user to know the imple-
Kevlin Henney is an independent consultant and trainer based in
the UK.
Kevlin Henney/kevlin@curbralan.com
Patterns In Java
Iteration constructs
have changed little
since days of yore,
but the subject of
iteration has been
objectified and
pattern-enriched
with collections
and iterators.
A tale of three patterns
http://www.javareport.com OCTOBER 2001 | Java™
Report 45
mentation type of the collection, and it is not without its
own overhead.
Iteration can be supported directly in the collection
by providing the collection with the notion of a current
position. Unfortunately, this restricts a collection to only
a single iteration at a time. The methods of the collection
cannot use the iteration mechanism for fear they may
upset an existing iteration; a collection may be refer-
enced by many objects, each with its own use for the
notion of a “current position,” and there is therefore a
strong possibility of interference between them. There is
also a question of cohesion—or rather the lack of it—
when a collection’s interface and implementation are
asked to represent both a collection of items and a cur-
rently selected item.
Solution. Place responsibility for iteration into an object
separate from the object being iterated over. The funda-
mental features of iteration must be supported, with the
most common division of features being for the collection
to support creation and initialization of an iterator object,
often using a FACTORY METHOD,3 and the iterator object
itself supporting the traversal features, either as sepa-
rate methods or as combined methods—COMMAND-QUERY
SEPARATION vs. COMBINED METHOD.1
From the standard java.util package, the Iterator and
Collection interface offer an example of the ITERATOR pattern
in action:
public interface Iterator
{
boolean hasNext();
Object next(); // Combined Method for advance and retrieve
...
}
public interface Collection
{
...
Iterator iterator(); // Factory Method
...
}
The underlying collection data structure is now fully
hidden, but without hiding complexity costs from the
user. There may be some additional overhead as a result
of creating an additional object and adding a managed
level of indirection. Whether this is significant depends
on the task the iteration is being carried out for and the
nature of the application.
The user is now freed from any dependency on imple-
mentation details—to the extent that a collection class may
be modified without affecting the code, or an alternative
collection type may be substituted, assuming an interface-
based approach is taken. It is even possible for the collec-
tion to be virtual in the sense there is no real collection of
objects at all, i.e., objects on an input stream or objects that
are calculated on the fly.
There is coupling between the iterator and the collec-
tion classes, suggesting the iterator class should be nested
within the collection class definition. It may be as a public
class in its own right or, more likely, a private inner or stat-
ic class implementing an interface such as java.util.Iterator.
If the iterator is simple, it may be reasonable to define it as
an anonymous inner class within the body of the actual
creation method.
Multiple traversals can now be supported, but the ques-
tion of validity arises if the collection is modified while the
iteration is carried out. The decision has to be taken as to
whether invalidating iterators is reasonable or not for a
given design, and then what to do about it.
• For small collections an iterator can take a snapshot of
the collection’s contents, i.e., such as using toArray and
iterate over that. This has the disadvantage of a costly
initialization, but the advantage of guaranteeing itera-
tion validity and content, even with multiple threads.
• Another approach to managing iterator validity is to
establish an OBSERVER relationship3 between the itera-
tor and the collection, so that the iterator is notified of
any changes in the collection, i.e., either invalidating
itself or advancing itself an element if its current ele-
ment is removed.
• A version stamp can also be used, so the collection has
a counter that is only modified when the collection
structure is modified. An iterator remembers the ver-
sion of its creation and always checks to see that the
target collection has not changed. This approach is
used in the Java Collections API, but has the disadvan-
tage that any change—even one that would not invali-
date the current iterator—will cause an exception to be
thrown.
• A more tolerant and laissez-faire approach is to only
throw an exception when the iterator absolutely can-
not perform an operation due to changes. For instance,
increasing the size of an array-based collection need
not invalidate iterators, but reducing the size below
the index of the current iterator would. Removing ele-
ments is generally safe from a linked list, and can also
be made safe if the current element is removed—either
the outgoing references continue to refer to adjacent
links to allow iteration to continue, or the outgoing
references are nulled, leading to an exception on the
next advance.
• The move to the next element, the extraction of the ele-
ment, and the check that it is actually there can all be
combined into a single method. This use of COMBINED
METHOD1 ensures that the traversal aspects of the loop
are uninterruptible and can be synchronized by the iter-
ator rather than the user of the iterator. This technique
can be combined with any of the strategies above. Note
that although java.util.Iterator has a COMBINED METHOD, it
does not fulfill the role just described.
The separation of iteration from the interface of the
collection means that collection users can customize
their own iteration by adapting the raw iterator, i.e.,
defining a search iterator that skips elements that do not
Patterns In Java
match some particular condition when it traverses.
Iteration Pattern 2: ENUMERATION METHOD
Support encapsulated iteration over a collection by placing
responsibility for iteration into a method on the collection.
Problem. Some collection types have representations
that do not conveniently support ITERATOR-based travers-
al. How can elements of such a collection be sequentially
and efficiently accessed without complicating and com-
promising the implementation of the collection?
For instance, a dictionary implemented as a sorted bina-
ry tree can be implemented minimally with each tree node
having a link to the child node on the left and on the right,
plus the actual data element, and so on recursively down
the subtrees. The subtree on the left has values that com-
pare lower than the data element, while those in the sub-
tree on the right compare higher:
public class SortedBinaryTree
{
...
private static class Node
{
String key, value;
Node left, right;
}
private Node root;
}
The simplest approach for visiting each element in
order is to recurse through the subtree on the left before
dealing with the key and value in the current node, and
then recurse through the subtree on the right. However,
this data structure will not easily support an iterator. The
traversal is broken up, and the context for recursion is
lost. One way to allow the iterator to retain context is to
add a parent link so the iterator can navigate both up and
down a tree:
public class SortedBinaryTree
{
...
private static class Node
{
String key, value;
Node left, right, up;
}
private Node root;
}
However, this complicates the management of the tree
and adds a small overhead—sometimes insignificant—to
each node. An alternative ITERATOR implementation does
not require a parent link, and captures the depth context
itself in a Stack:
public class SortedBinaryTree
{
public class static Iterator implements java.util.Iterator
{
...
private java.util.Stack nodes; // nodes to revisit
}
...
}
The stack places the complexity in the iterator rather
than the collection, but can be fragile if the collection’s
structure changes during iteration.
In each case, there are further issues if something like
the standard Iterator interface is used for a dictionary. It
provides only for returning a single value, and so a com-
bined data structure to represent the key-value pair must
be used. Note that this problem does not arise if COMMAND-
QUERY SEPARATION is used.
More generally, there are times when a collection
requires some pre- and post-iteration code to be executed
before and after the traversal. The most obvious and com-
mon case is synchronization against threaded interruption.
Leaving users to do it for themselves is tedious and error
prone and, specifically referring to thread synchronization,
a synchronized block is problematic because it can give the
illusion of safety without any of the safety.1
Solution. Bring the iteration inside the collection and
encapsulate it in a single method responsible for complete
traversal. The task of the loop—what would normally be
its body—is passed in as a COMMAND object3 and is applied
to each element in turn (see Listing 1).
The method applies any of the relevant pre- and post-
iteration actions itself, performing the loop in between,
effectively atomically. Different loop strategies can be sup-
ported easily by adding new methods, rather than requir-
ing a whole new object type, i.e., for pre-order traversal.
This is particularly useful for recursive data structures,
such as COMPOSITE objects.3
The ENUMERATION METHOD4 is a fundamental iteration
pattern that encapsulates the actual control flow of the
traversal loop. There are strong similarities with the
TEMPLATE METHOD design pattern,3 as well as VISITOR3 and
EXECUTE-AROUND METHOD.2 ENUMERATION METHOD can be
considered an inversion of the ITERATOR model, both in
terms of its flow of control and responsibilities. The per-
formance of an ENUMERATION METHOD is directly compara-
ble to that of an ITERATOR.
Iteration Pattern 3: BATCH METHOD
Group multiple collection accesses together to reduce the
cost of multiple individual accesses.
Problem. How can many actions be treated atomically?
In particular, how can multiple operations and accesses on
a collection be handled efficiently and without interrup-
tion? In a distributed system—or any other environment
involving access latency, such as database access—iterated
simple operations use up bandwidth:
Patterns In Java
46 Java™
Report | OCTOBER 2001 http://www.javareport.com
http://www.javareport.com OCTOBER 2001 | Java™
Report 47
for(each key of interest)
{
...
dictionary.put(key, value);
}
for(each key of interest)
{
value = dictionary.get(key);
...
}
While ITERATOR allows traversal of a sequence in an
abstract and controlled fashion, it does not itself address
concurrency and efficiency issues. A COMBINED METHOD
addresses the basic concurrency issues, and can fold three
operations into one; however, this only reduces the num-
ber of accesses, not the number of times a cost-incurring
loop is performed.
Solution. Define a single method that performs the
action repeatedly. The method is declared to take all the
arguments for each execution of the action, i.e., an array or
collection, and to return results by similar means. This
single method folds the repetition into a data structure
rather than a loop, so that looping is performed before or
after the method call, in preparation or in follow up.
Therefore, the cost of access is reduced to a single access,
or a few “chunked” accesses:
interface RemoteDictionary ...
{
Object[] get(Object[] keys);
void put(Object[] keys, Object[] values);
...
}
Each method access is now more expensive, but the
overall cost has been reduced. Such accesses can also be
synchronized as appropriate within the method call. The
trade-off in complexity is that significantly more house-
keeping is performed to set up and work with the results
of the call, and more intermediate data structures are
required. The BATCH METHOD pattern is found in many
distributed system architectures, such as the CORBA
Common Object Services.5 It can be considered as taking
the COMBINED METHOD pattern to its logical extreme in com-
bining many iterations into a single shot.
Conclusion
What drives pattern-based design is not that patterns
embody neat fragments of design—although this is often
true—but that any given pattern can be considered in ten-
sion with one or more other patterns. These other pat-
terns compete as design alternatives, with the trade-offs
in their forces and consequences making all the differ-
ence, pulling the design one way and another. Sometimes
there is a clear winner and the consideration of alterna-
tives does not add anything except time spent mulling
over the detail at the water cooler, on the whiteboard, or
on the way home. However, at other times having a
default case you always apply, without question, can
have quite the opposite effect, accidentally brushing sig-
nificant concerns under the carpet. It is here that having
patterns presented together and in opposition captures
more of the spirit of the design, even in something as
humble and everyday as iteration. s
References
1. Henney, K. “A Tale of Two Patterns,” Java Report,
Vol. 5, No. 12, December 2000, available at http://www.
curbralan.com.
2. Henney, K. “Another Tale of Two Patterns,” Java Report,
Vol. 6, No. 3, March 2001, available at http://www.
curbralan.com.
3. Gamma, E., et al. Design Patterns: Elements of Reusable
Object-Oriented Software, Addison-Wesley, 1995.
4. Beck, K. Smalltalk Best Practice Patterns, Prentice Hall,
1997.
5. Object Management Group (OMG). CORBAservices:
The Common Object Services Specification, available at
http://www.omg.org.
Patterns In Java
Iteration over a sorted binary tree using recursive descent in
an enumeration method
public interface KeyValueTask
{
void apply(String key, String value);
}
public class SortedBinaryTree
{
public synchronized void forEachDo(KeyValueTask toDo)
{
forEachDo(toDo, root);
}
private void forEachDo(KeyValueTask toDo, Node node)
{
if(node != null)
{
forEachDo(toDo, node.left);
toDo.apply(node.key, node.value);
forEachDo(toDo, node.right);
}
}
...
}
tree.forEachDo(new KeyValueTask() {
public void apply(String key, String value)
{ System.out.println(key + “ -> “ + value); }
});
LISTING 1

More Related Content

PDF
Defaultification Refactoring: A Tool for Automatically Converting Java Method...
ODP
EJB 3.0 Walkthrough (2006)
PPTX
Structural pattern 3
PPTX
Effective Java - Chapter 2: Creating and Destroying Objects
PDF
java-06inheritance
PPTX
Effective Java - Chapter 4: Classes and Interfaces
PDF
Automated Refactoring of Legacy Java Software to Default Methods Talk at GMU
PPTX
PATTERNS03 - Behavioural Design Patterns
Defaultification Refactoring: A Tool for Automatically Converting Java Method...
EJB 3.0 Walkthrough (2006)
Structural pattern 3
Effective Java - Chapter 2: Creating and Destroying Objects
java-06inheritance
Effective Java - Chapter 4: Classes and Interfaces
Automated Refactoring of Legacy Java Software to Default Methods Talk at GMU
PATTERNS03 - Behavioural Design Patterns

What's hot (7)

PPT
Introduction to design_patterns
DOCX
Oracle plsql and d2 k interview questions
DOCX
Oracle plsql and d2 k interview question1
PDF
Towards Improving Interface Modularity in Legacy Java Software Through Automa...
PDF
Introducing generic types
PDF
Automated Refactoring of Legacy Java Software to Default Methods Talk at ICSE...
PDF
Poster on Automated Refactoring of Legacy Java Software to Default Methods
Introduction to design_patterns
Oracle plsql and d2 k interview questions
Oracle plsql and d2 k interview question1
Towards Improving Interface Modularity in Legacy Java Software Through Automa...
Introducing generic types
Automated Refactoring of Legacy Java Software to Default Methods Talk at ICSE...
Poster on Automated Refactoring of Legacy Java Software to Default Methods
Ad

Viewers also liked (18)

PDF
Creating Stable Assignments
PDF
Introducing the FLUID Principles
PDF
The web you were used to is gone. Architecture and strategy for your mobile c...
PDF
97 Things Every Programmer Should Know
PDF
Keynote: Small Is Beautiful - Kevlin Henney - Codemotion Rome 2015
PDF
A Tale of Two Patterns
PDF
DPC2007 Objects Of Desire (Kevlin Henney)
 
PDF
Seven Ineffective Coding Habits of Many Java Programmers
PDF
Patterns of Value
PDF
Worse Is Better, for Better or for Worse
PDF
SOLID Deconstruction
PDF
Collections for States
PDF
Substitutability
PDF
Framing the Problem
PDF
Driven to Tests
PDF
Immutability FTW!
PDF
The Error of Our Ways
PDF
Worse Is Better, for Better or for Worse
Creating Stable Assignments
Introducing the FLUID Principles
The web you were used to is gone. Architecture and strategy for your mobile c...
97 Things Every Programmer Should Know
Keynote: Small Is Beautiful - Kevlin Henney - Codemotion Rome 2015
A Tale of Two Patterns
DPC2007 Objects Of Desire (Kevlin Henney)
 
Seven Ineffective Coding Habits of Many Java Programmers
Patterns of Value
Worse Is Better, for Better or for Worse
SOLID Deconstruction
Collections for States
Substitutability
Framing the Problem
Driven to Tests
Immutability FTW!
The Error of Our Ways
Worse Is Better, for Better or for Worse
Ad

Similar to A Tale of Three Patterns (20)

PDF
‘go-to’ general-purpose sequential collections - from Java To Scala
DOC
24 collections framework interview questions
DOCX
Java mcq
DOC
Java interview questions
PDF
Conventional and Reasonable
PDF
Something for Nothing
DOCX
Java interview questions
PDF
Absolute C++ 5th Edition Savitch Solutions Manual
PDF
Top 371 java fa qs useful for freshers and experienced
PDF
Java Faqs useful for freshers and experienced
PDF
Instantly download the full Absolute C++ 5th Edition Savitch Solutions Manual...
PPTX
1. Java Collections Framework Introduction
DOCX
Intervies
PDF
The 23 gof design patterns in java ,the summary
PDF
The 23 gof design patterns in java ,the summary
PDF
Core_Java_Interview.pdf
PDF
Opposites Attract
PDF
Absolute C++ 5th Edition Savitch Solutions Manual
PDF
Absolute C++ 5th Edition Savitch Solutions Manual
PDF
Absolute C++ 5th Edition Savitch Solutions Manual
‘go-to’ general-purpose sequential collections - from Java To Scala
24 collections framework interview questions
Java mcq
Java interview questions
Conventional and Reasonable
Something for Nothing
Java interview questions
Absolute C++ 5th Edition Savitch Solutions Manual
Top 371 java fa qs useful for freshers and experienced
Java Faqs useful for freshers and experienced
Instantly download the full Absolute C++ 5th Edition Savitch Solutions Manual...
1. Java Collections Framework Introduction
Intervies
The 23 gof design patterns in java ,the summary
The 23 gof design patterns in java ,the summary
Core_Java_Interview.pdf
Opposites Attract
Absolute C++ 5th Edition Savitch Solutions Manual
Absolute C++ 5th Edition Savitch Solutions Manual
Absolute C++ 5th Edition Savitch Solutions Manual

More from Kevlin Henney (20)

PDF
Program with GUTs
PDF
The Case for Technical Excellence
PDF
Empirical Development
PDF
Lambda? You Keep Using that Letter
PDF
Lambda? You Keep Using that Letter
PDF
Solid Deconstruction
PDF
Get Kata
PDF
Procedural Programming: It’s Back? It Never Went Away
PDF
Structure and Interpretation of Test Cases
PDF
Agility ≠ Speed
PDF
Refactoring to Immutability
PDF
Old Is the New New
PDF
Turning Development Outside-In
PDF
Giving Code a Good Name
PDF
Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...
PDF
Thinking Outside the Synchronisation Quadrant
PDF
Code as Risk
PDF
Software Is Details
PDF
Game of Sprints
PDF
Good Code
Program with GUTs
The Case for Technical Excellence
Empirical Development
Lambda? You Keep Using that Letter
Lambda? You Keep Using that Letter
Solid Deconstruction
Get Kata
Procedural Programming: It’s Back? It Never Went Away
Structure and Interpretation of Test Cases
Agility ≠ Speed
Refactoring to Immutability
Old Is the New New
Turning Development Outside-In
Giving Code a Good Name
Clean Coders Hate What Happens To Your Code When You Use These Enterprise Pro...
Thinking Outside the Synchronisation Quadrant
Code as Risk
Software Is Details
Game of Sprints
Good Code

Recently uploaded (20)

PDF
PTS Company Brochure 2025 (1).pdf.......
PPTX
CHAPTER 2 - PM Management and IT Context
PDF
wealthsignaloriginal-com-DS-text-... (1).pdf
PPTX
Embracing Complexity in Serverless! GOTO Serverless Bengaluru
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 41
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PDF
Digital Strategies for Manufacturing Companies
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PDF
Designing Intelligence for the Shop Floor.pdf
PDF
medical staffing services at VALiNTRY
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
PPTX
VVF-Customer-Presentation2025-Ver1.9.pptx
PDF
top salesforce developer skills in 2025.pdf
PDF
Design an Analysis of Algorithms I-SECS-1021-03
PPTX
history of c programming in notes for students .pptx
PDF
Digital Systems & Binary Numbers (comprehensive )
PDF
2025 Textile ERP Trends: SAP, Odoo & Oracle
PDF
System and Network Administraation Chapter 3
PDF
Which alternative to Crystal Reports is best for small or large businesses.pdf
PDF
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool
PTS Company Brochure 2025 (1).pdf.......
CHAPTER 2 - PM Management and IT Context
wealthsignaloriginal-com-DS-text-... (1).pdf
Embracing Complexity in Serverless! GOTO Serverless Bengaluru
Internet Downloader Manager (IDM) Crack 6.42 Build 41
How to Migrate SBCGlobal Email to Yahoo Easily
Digital Strategies for Manufacturing Companies
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
Designing Intelligence for the Shop Floor.pdf
medical staffing services at VALiNTRY
Internet Downloader Manager (IDM) Crack 6.42 Build 42 Updates Latest 2025
VVF-Customer-Presentation2025-Ver1.9.pptx
top salesforce developer skills in 2025.pdf
Design an Analysis of Algorithms I-SECS-1021-03
history of c programming in notes for students .pptx
Digital Systems & Binary Numbers (comprehensive )
2025 Textile ERP Trends: SAP, Odoo & Oracle
System and Network Administraation Chapter 3
Which alternative to Crystal Reports is best for small or large businesses.pdf
Claude Code: Everyone is a 10x Developer - A Comprehensive AI-Powered CLI Tool

A Tale of Three Patterns

  • 1. 44 Java™ Report | OCTOBER 2001 http://www.javareport.com T HE CONTROL-FLOW structures of Java have remained fairly stable since their arrival in C three decades ago. They express the core structured- programming primitives of sequential, selective, and repetitive execution, as well as discontinuous control flow, such as breaking from a loop. Selective execution is much as it used to be, except it has lost some ground to the use of polymorphism. The basic refinement to sequential execution has been its disruption through exceptions and its multiplication through threading, both of which are supported in the heart of the language. My previous two columns1, 2 explored patterns that cap- tured differences in practice between single-threaded and multi-threaded programming, and exception-free and exception-throwing code. Iteration constructs have changed little since days of yore, but the subject of iteration has been objectified and pattern-enriched with collections and iterators. To begin at the beginning, there are five features that define any iteration: • The initialization to start the loop. • The continuation condition to keep it running (or termi- nation condition to stop it, depending on whether you regard the glass as half-full or half-empty). • The body of the loop to do the work. • The advancement of the iteration to go around again. This may be a distinct action, i.e., an increment, or a side effect of something in the body of the loop. • The finalization to clean up after the loop. This feature is often optional, a no-op. It is no coincidence that the four mandatory parts of a loop correspond to the anatomy of the for. The ITERATOR pattern3 represents what many OO devel- opers think of as the design for iteration in an object sys- tem, but there is more to iteration abstraction than just ITERATOR. The rest of this column looks at three iteration patterns whose solutions differ in their response to thread- ing, distribution, exceptions, and parameterization. So let’s start by looking in detail at something that should be fairly familiar. Iteration Pattern 1: ITERATOR Support iteration over an encapsulated collection by plac- ing responsibility for iteration into a separate object. Problem. How can elements of a collection be accessed conveniently, sequentially, and efficiently without exposing its underlying representation or making it less cohesive? If the representation of a collection is accessible, users can access the internal struc- ture of the object directly so they can iterate over it. However, users can under- mine its structure, intention- ally or otherwise, giving rise to subtle bugs or assumptions about undocumented class behavior. Their code is also strongly coupled to the imple- mentation details of the collection, so any changes to the data structure will inevitably break the client code, and any change of collection type will inevitably cause a rewrite. It is not possible to work reasonably through an interface if the implementation of a collection must be known in order to use it. It is tempting to use a conventional integer index to look up elements. However, this is an abstraction too far, hiding potentially expensive operations behind an inno- cent-looking interface. To loop over every element in an array-based sequence with an index is a linear-time oper- ation (O(N) in O-notation), with the generated code visit- ing each element precisely once in constant time. To do the same for a linked-list implementation is significantly more expensive (a pricey O(N2)) as previously visited links in the list are retraversed each time to find the next indexed element. To get a feel for what this means in practice, an array of 10 elements will require 10 accesses, whereas a list of 10 will require 55 link traversals. But where an array of 100,000 elements requires 100,000 accesses, a list of the same length requires more than 5 billion link traversals. Hiding such a profound difference between a random-access structure and a sequential- access structure behind a weakly specified get interface (no non-functional guarantees or warnings are given) is questionable design. In sequential-access cases, it can be more effective to make use of a toArray method to get a snapshot of all the elements and iterate over the returned array instead. However, this still requires the user to know the imple- Kevlin Henney is an independent consultant and trainer based in the UK. Kevlin Henney/kevlin@curbralan.com Patterns In Java Iteration constructs have changed little since days of yore, but the subject of iteration has been objectified and pattern-enriched with collections and iterators. A tale of three patterns
  • 2. http://www.javareport.com OCTOBER 2001 | Java™ Report 45 mentation type of the collection, and it is not without its own overhead. Iteration can be supported directly in the collection by providing the collection with the notion of a current position. Unfortunately, this restricts a collection to only a single iteration at a time. The methods of the collection cannot use the iteration mechanism for fear they may upset an existing iteration; a collection may be refer- enced by many objects, each with its own use for the notion of a “current position,” and there is therefore a strong possibility of interference between them. There is also a question of cohesion—or rather the lack of it— when a collection’s interface and implementation are asked to represent both a collection of items and a cur- rently selected item. Solution. Place responsibility for iteration into an object separate from the object being iterated over. The funda- mental features of iteration must be supported, with the most common division of features being for the collection to support creation and initialization of an iterator object, often using a FACTORY METHOD,3 and the iterator object itself supporting the traversal features, either as sepa- rate methods or as combined methods—COMMAND-QUERY SEPARATION vs. COMBINED METHOD.1 From the standard java.util package, the Iterator and Collection interface offer an example of the ITERATOR pattern in action: public interface Iterator { boolean hasNext(); Object next(); // Combined Method for advance and retrieve ... } public interface Collection { ... Iterator iterator(); // Factory Method ... } The underlying collection data structure is now fully hidden, but without hiding complexity costs from the user. There may be some additional overhead as a result of creating an additional object and adding a managed level of indirection. Whether this is significant depends on the task the iteration is being carried out for and the nature of the application. The user is now freed from any dependency on imple- mentation details—to the extent that a collection class may be modified without affecting the code, or an alternative collection type may be substituted, assuming an interface- based approach is taken. It is even possible for the collec- tion to be virtual in the sense there is no real collection of objects at all, i.e., objects on an input stream or objects that are calculated on the fly. There is coupling between the iterator and the collec- tion classes, suggesting the iterator class should be nested within the collection class definition. It may be as a public class in its own right or, more likely, a private inner or stat- ic class implementing an interface such as java.util.Iterator. If the iterator is simple, it may be reasonable to define it as an anonymous inner class within the body of the actual creation method. Multiple traversals can now be supported, but the ques- tion of validity arises if the collection is modified while the iteration is carried out. The decision has to be taken as to whether invalidating iterators is reasonable or not for a given design, and then what to do about it. • For small collections an iterator can take a snapshot of the collection’s contents, i.e., such as using toArray and iterate over that. This has the disadvantage of a costly initialization, but the advantage of guaranteeing itera- tion validity and content, even with multiple threads. • Another approach to managing iterator validity is to establish an OBSERVER relationship3 between the itera- tor and the collection, so that the iterator is notified of any changes in the collection, i.e., either invalidating itself or advancing itself an element if its current ele- ment is removed. • A version stamp can also be used, so the collection has a counter that is only modified when the collection structure is modified. An iterator remembers the ver- sion of its creation and always checks to see that the target collection has not changed. This approach is used in the Java Collections API, but has the disadvan- tage that any change—even one that would not invali- date the current iterator—will cause an exception to be thrown. • A more tolerant and laissez-faire approach is to only throw an exception when the iterator absolutely can- not perform an operation due to changes. For instance, increasing the size of an array-based collection need not invalidate iterators, but reducing the size below the index of the current iterator would. Removing ele- ments is generally safe from a linked list, and can also be made safe if the current element is removed—either the outgoing references continue to refer to adjacent links to allow iteration to continue, or the outgoing references are nulled, leading to an exception on the next advance. • The move to the next element, the extraction of the ele- ment, and the check that it is actually there can all be combined into a single method. This use of COMBINED METHOD1 ensures that the traversal aspects of the loop are uninterruptible and can be synchronized by the iter- ator rather than the user of the iterator. This technique can be combined with any of the strategies above. Note that although java.util.Iterator has a COMBINED METHOD, it does not fulfill the role just described. The separation of iteration from the interface of the collection means that collection users can customize their own iteration by adapting the raw iterator, i.e., defining a search iterator that skips elements that do not Patterns In Java
  • 3. match some particular condition when it traverses. Iteration Pattern 2: ENUMERATION METHOD Support encapsulated iteration over a collection by placing responsibility for iteration into a method on the collection. Problem. Some collection types have representations that do not conveniently support ITERATOR-based travers- al. How can elements of such a collection be sequentially and efficiently accessed without complicating and com- promising the implementation of the collection? For instance, a dictionary implemented as a sorted bina- ry tree can be implemented minimally with each tree node having a link to the child node on the left and on the right, plus the actual data element, and so on recursively down the subtrees. The subtree on the left has values that com- pare lower than the data element, while those in the sub- tree on the right compare higher: public class SortedBinaryTree { ... private static class Node { String key, value; Node left, right; } private Node root; } The simplest approach for visiting each element in order is to recurse through the subtree on the left before dealing with the key and value in the current node, and then recurse through the subtree on the right. However, this data structure will not easily support an iterator. The traversal is broken up, and the context for recursion is lost. One way to allow the iterator to retain context is to add a parent link so the iterator can navigate both up and down a tree: public class SortedBinaryTree { ... private static class Node { String key, value; Node left, right, up; } private Node root; } However, this complicates the management of the tree and adds a small overhead—sometimes insignificant—to each node. An alternative ITERATOR implementation does not require a parent link, and captures the depth context itself in a Stack: public class SortedBinaryTree { public class static Iterator implements java.util.Iterator { ... private java.util.Stack nodes; // nodes to revisit } ... } The stack places the complexity in the iterator rather than the collection, but can be fragile if the collection’s structure changes during iteration. In each case, there are further issues if something like the standard Iterator interface is used for a dictionary. It provides only for returning a single value, and so a com- bined data structure to represent the key-value pair must be used. Note that this problem does not arise if COMMAND- QUERY SEPARATION is used. More generally, there are times when a collection requires some pre- and post-iteration code to be executed before and after the traversal. The most obvious and com- mon case is synchronization against threaded interruption. Leaving users to do it for themselves is tedious and error prone and, specifically referring to thread synchronization, a synchronized block is problematic because it can give the illusion of safety without any of the safety.1 Solution. Bring the iteration inside the collection and encapsulate it in a single method responsible for complete traversal. The task of the loop—what would normally be its body—is passed in as a COMMAND object3 and is applied to each element in turn (see Listing 1). The method applies any of the relevant pre- and post- iteration actions itself, performing the loop in between, effectively atomically. Different loop strategies can be sup- ported easily by adding new methods, rather than requir- ing a whole new object type, i.e., for pre-order traversal. This is particularly useful for recursive data structures, such as COMPOSITE objects.3 The ENUMERATION METHOD4 is a fundamental iteration pattern that encapsulates the actual control flow of the traversal loop. There are strong similarities with the TEMPLATE METHOD design pattern,3 as well as VISITOR3 and EXECUTE-AROUND METHOD.2 ENUMERATION METHOD can be considered an inversion of the ITERATOR model, both in terms of its flow of control and responsibilities. The per- formance of an ENUMERATION METHOD is directly compara- ble to that of an ITERATOR. Iteration Pattern 3: BATCH METHOD Group multiple collection accesses together to reduce the cost of multiple individual accesses. Problem. How can many actions be treated atomically? In particular, how can multiple operations and accesses on a collection be handled efficiently and without interrup- tion? In a distributed system—or any other environment involving access latency, such as database access—iterated simple operations use up bandwidth: Patterns In Java 46 Java™ Report | OCTOBER 2001 http://www.javareport.com
  • 4. http://www.javareport.com OCTOBER 2001 | Java™ Report 47 for(each key of interest) { ... dictionary.put(key, value); } for(each key of interest) { value = dictionary.get(key); ... } While ITERATOR allows traversal of a sequence in an abstract and controlled fashion, it does not itself address concurrency and efficiency issues. A COMBINED METHOD addresses the basic concurrency issues, and can fold three operations into one; however, this only reduces the num- ber of accesses, not the number of times a cost-incurring loop is performed. Solution. Define a single method that performs the action repeatedly. The method is declared to take all the arguments for each execution of the action, i.e., an array or collection, and to return results by similar means. This single method folds the repetition into a data structure rather than a loop, so that looping is performed before or after the method call, in preparation or in follow up. Therefore, the cost of access is reduced to a single access, or a few “chunked” accesses: interface RemoteDictionary ... { Object[] get(Object[] keys); void put(Object[] keys, Object[] values); ... } Each method access is now more expensive, but the overall cost has been reduced. Such accesses can also be synchronized as appropriate within the method call. The trade-off in complexity is that significantly more house- keeping is performed to set up and work with the results of the call, and more intermediate data structures are required. The BATCH METHOD pattern is found in many distributed system architectures, such as the CORBA Common Object Services.5 It can be considered as taking the COMBINED METHOD pattern to its logical extreme in com- bining many iterations into a single shot. Conclusion What drives pattern-based design is not that patterns embody neat fragments of design—although this is often true—but that any given pattern can be considered in ten- sion with one or more other patterns. These other pat- terns compete as design alternatives, with the trade-offs in their forces and consequences making all the differ- ence, pulling the design one way and another. Sometimes there is a clear winner and the consideration of alterna- tives does not add anything except time spent mulling over the detail at the water cooler, on the whiteboard, or on the way home. However, at other times having a default case you always apply, without question, can have quite the opposite effect, accidentally brushing sig- nificant concerns under the carpet. It is here that having patterns presented together and in opposition captures more of the spirit of the design, even in something as humble and everyday as iteration. s References 1. Henney, K. “A Tale of Two Patterns,” Java Report, Vol. 5, No. 12, December 2000, available at http://www. curbralan.com. 2. Henney, K. “Another Tale of Two Patterns,” Java Report, Vol. 6, No. 3, March 2001, available at http://www. curbralan.com. 3. Gamma, E., et al. Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1995. 4. Beck, K. Smalltalk Best Practice Patterns, Prentice Hall, 1997. 5. Object Management Group (OMG). CORBAservices: The Common Object Services Specification, available at http://www.omg.org. Patterns In Java Iteration over a sorted binary tree using recursive descent in an enumeration method public interface KeyValueTask { void apply(String key, String value); } public class SortedBinaryTree { public synchronized void forEachDo(KeyValueTask toDo) { forEachDo(toDo, root); } private void forEachDo(KeyValueTask toDo, Node node) { if(node != null) { forEachDo(toDo, node.left); toDo.apply(node.key, node.value); forEachDo(toDo, node.right); } } ... } tree.forEachDo(new KeyValueTask() { public void apply(String key, String value) { System.out.println(key + “ -> “ + value); } }); LISTING 1