Loops & Iterators... in Java!
Thomas J. Kennedy
Iterators are an interesting and powerful design paradigm.
One could claim that iterators are not design, and that any discussion of iterators should be in a writing code module. However, we have only looked at the C++ iterator interface. There are iterators in C++, Java, Python 3, and many other languages.
1 A Quick Review of the Class Checklist
Did that prose sound familiar? Hopefully it did. Earlier this semester we spent a great deal of time talking about iterators in C++. In fact iterators have an entire row (technically two rows) in the Cross Language Class Checklist.
Example 1: Cross Language Class Checklist
C++ Java Python 3 Rust Default Constructor Default Constructor __init__
new()
or Default traitCopy Constructor Clone and/or Copy Constructor __deepcopy__
Clone trait Destructor finalize (deprecated/discouraged) __del__
Drop trait Assignment Operator (=) Accessors (Getters) Accessors (Getters) Accessors ( @property
)Accessors (Getters) Mutators (Setters) Mutators (Setters) Setter ( @attribute.setter
)Mutators (setters) Swap Logical Equivalence Operator (==) equals __eq__
std::cmp::PartialEq trait Less-Than / Comes-Before Operator (<) hashCode __hash__
std::cmp::PartialOrd trait Stream Insertion Operator (<<) toString __str__
std::fmt::Display trait __repr__
std::fmt::Debug trait begin()
andend()
iterator
__iter__
iter()
anditer_mut()
Let us zoom in on two (2) rows:
Example 2: Cross Language Class Checklist - Just Iterators
C++ Java Python 3 Rust begin()
andend()
iterator
__iter__
iter()
anditer_mut()
Depending on the language, there may be a distinction between:
- Read Only iterators (e.g., C++
const_iterator
). - Read-and-Write iterators (e.g., C++
iterator
).
Since our focus is Java (where such a distinction is no oft made) we will assume iterators provide read and write access in all examples.
2 The Loops
In C++ we ended up with two iterator loops, a while
loop and a range based for
loop. Let us work backwards from the range based for
loop.
C++
ArbitraryContainer<T> collection;
for (T oneEntry : collection) {
// do stuff
}
Java
ArbitraryContainer<T> collection = new ArbitraryContainer<T>();
for (T oneEntry : collection) {
// do stuff
}
Do you see the difference? No? The loop itself is syntactically identical. I will continue use range based for
loops as often as possible (syntactic sugar).
The while
loop is a little more involved… The C++ while loop took the form:
ArbitraryContainer<T> collection;
ArbitraryContainer<T>::iterator it = collection.begin();
while (it < collection.end()) {
// do stuff
it++;
}
The Java version is close… but definitely not identical.
ArbitraryContainer<T> collection = new ArbitraryContainer<T>();
Iterator<T> it = collection.iterator();
while (it.hasNext()) {
// do stuff
T theRetrievedValue = it.next();
}
We still find the three fundamental traversal-loop operations.
Operation | C++ | Java |
---|---|---|
Initialization | it = collection.begin() |
it = collection.iterator() |
Increment | it++ |
T theRetrievedValue = it.next() |
Stop Condition | it < collection.end() |
it.hasNext() |
There is a key difference between the C++ iterator interface and the Java iterator interface… responsibilities.
In C++ the ArbitraryCollection
provides
- the iterator with
ArbitraryCollection::begin()
- support for a boundary check with
ArbitraryCollection::end()
.
In Java (and Python, and Rust) the ArbitraryCollection
provides the iterator and nothing else. The boundary check is handled exclusively by the iterator.
3 The Subtle Difference
In C++ the dereference operation
someVar = *it;
and increment operation
it++;
are usually separate. In Java the dereference and increment operations are combined into a single step.
someVar = it.next();