"Hi, Amigo!"

"Hi, Ellie!"

"Today I want to tell you about iterators."

"Iterators were invented practically at the same time as collections. The main purpose of collections is to store elements, and the main purpose of an iterator is to retrieve these elements one by one."

"What's so difficult about getting a set of elements?"

"First, the elements in some collections, such as Set, don't have an established order and/or the order changes constantly."

"Second, some data structures may store objects in a very complex way: in different groups, lists, etc. In other words, handing out all the elements in order would be a non-trivial task."

"Third, collections tend to change. Suppose you decide to display the entire contents of a collection, but right in the middle of the output the JVM switches to another thread that replaces half of the collection's elements. So instead of the output, you get who knows what."

"Hmm..."

"But! These are precisely the sort of problems that an iterator can solve. An iterator is a special object within a collection that, on the one hand, has access to all its private data and knows its internal structure, and on the other hand, implements the public Iterator interface, which lets everyone know how to work with it."

"Some iterators have an internal array into which all elements of the collection are copied when the iterator is created. This ensures that any subsequent changes to the collection won't affect the number or order of the elements."

"I think you have come across this when working with for each. You can't simultaneously loop over a collection and remove elements from it. This is all precisely because of the way an iterator works."

"In the new collections added to the concurrency library, the iterator is reworked to eliminate this problem."

"Let me remind you how an iterator works."

"Java has a special Iterator interface. Here are its methods:"

Methods of the Iterator<E> interface Description
boolean hasNext() Checks if there are any more elements
E next() Returns the current element and moves to the next.
void remove() Removes the current element

"An iterator lets you successively get all the elements of a collection. It's more logical to think of an iterator as something like an InputStream — it has all the data, but its task is to output it sequentially."

"The  next() method returns the next element in the collection."

"The hasNext() method is used to check if there are any more elements."

"And remove() removes the current element."

"Any questions?"

"Why do the methods have such strange names? Why not isEmpty() and getNextElement()?"

"Wouldn't that make more sense?"

"It would make more sense, but the names came from the C++ language, where iterators appeared earlier."

"I see. Let's continue."

"In addition to an iterator, there is also the Iterable interface, which must be implemented by all collections that support iterators. It has a single method:"

Methods of the Iterable<T> interface Description
Iterator<T>iterator() Returns an iterator object

"You can use this method on any collection to get an iterator object to walk through its elements. Let's walk over all the elements of in a TreeSet:"

Example
TreeSet<String> set = new TreeSet<String>();
Iterator<String> iterator = set.iterator();

while (iterator.hasNext())
{
 String item = iterator.next();
 System.out.println(item);
}

"Using an iterator like this isn't very convenient — there's too much superfluous and obvious code. The situation became simpler when the for-each loop appeared in Java."

"Now this code is much more compact and readable:"

Before After
TreeSet<String> set = new TreeSet<String>();
Iterator<String> iterator = set.iterator();

while (iterator.hasNext())
{
 String item = iterator.next();
 System.out.println(item);
}
TreeSet<String> set = new TreeSet<String>();

for(String item : set)
{
 System.out.println(item);
}

"This is the same code! The iterator is used in both cases."

"It's just that its use is hidden in the for-each loop. Note that the code on the right has no red text at all. The use of the iterator is completely hidden."

"A for-each loop be used for any objects that support iterators. In other words, you can write your own class, add the iterator() method to it, and use its objects in a for-each construct."

"Wow! Of course, I'm not eager to write my own collections and iterators, but the prospect is still tempting. I'll make a note of it."

Additionally, there's another popular type of iterator that even has its own interface. I'm talking about an iterator for lists, i.e. ListIterator.

"Regardless of their implementation, lists maintain the order of elements, which makes working with them through an iterator a little more conveniently."

"Here are the methods of the ListIterator<E> interface:"

Method Description
boolean hasNext() Checks if there are any more elements ahead.
E next() Returns the next element.
int nextIndex() Returns the index of the next element
void set(E e) Changes the value of the current element
boolean hasPrevious() Checks if there are any elements behind.
E previous() Returns the previous element
int previousIndex() Returns the index of the previous element
void remove() Removes the current element
void add(E e) Adds an element to the end of the list.

"In other words, here we can move both forward and backward. And there are a couple of other small features."

"Well, that's interesting stuff. Where is it used?"

"Suppose you want to move back and forth on a linked list. The get operation will be rather slow, but the next() operation will be very fast."

"Hmm. You convinced me. I'll keep it in mind."

"Thanks, Ellie!"