Loops & Iterators... in Java!

Thomas J. Kennedy

Contents:

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 trait
Copy 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() and end() iterator __iter__ iter() and iter_mut()

Let us zoom in on two (2) rows:

Example 2: Cross Language Class Checklist - Just Iterators
C++ Java Python 3 Rust
begin() and end() iterator __iter__ iter() and iter_mut()

Depending on the language, there may be a distinction between:

  1. Read Only iterators (e.g., C++ const_iterator).
  2. 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

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();