4

I have a doubt with the next() method on iterators. If I have as a part of my code this lines (with arrayOfStrings size = 4):

Iterator<String> it = arrayOfStrings.iterator(); //arrayOfString is ArrayList<String>

while(it.hasNext()) {
    String e = it.next();
    System.out.println(e);
}

At the very first iteration, the iterator starts pointing to element with index 0? or like the "index -1" ?

I ask because as far as I know the next() method returns the next element in the collection.

So, if at the very first iteration the iterator starts at index 0 when next() is invoked, it returns the element at index 1 and I won´t be able to do nothing with the element at index 0?

blurfus
  • 13,485
  • 8
  • 55
  • 61
Angelixus
  • 160
  • 1
  • 5
  • 13
  • 1
    The code you show should correctly print **all elements** of the `ArrayList`. The `it.next()` call will, at its first call, also return the **first element**. This element is usually denoted with **index 0**. – Zabuzard Dec 06 '17 at 19:40
  • 1
    Did you know you can look at the source code of java classes to see what they do and how? – takendarkk Dec 06 '17 at 19:40
  • Possible duplicate of [Ways to iterate over a List in java?](https://stackoverflow.com/questions/18410035/ways-to-iterate-over-a-list-in-java) – user1803551 Dec 06 '17 at 19:44
  • Think of iterator as a cursor when you are typing text, imagine you had "abc" in some text file, and you want to read each and every one of those letters, at the very beginning cursor will be just before letter 'a' when you call next imagine that it moves one place to the right and selects the element it moves over, so you can now print that element or do something with it, then on the next call it will move over across 'b' so you can do something with 'b', and it keeps doing this until it has nothing to move over. – whatamidoingwithmylife Dec 06 '17 at 19:44
  • @user1803551 OP is not asking how to iterate over a List - OP is asking about the mechanics of iterating using `next()` and, specifically, the edge case when fetching the first element. – blurfus Dec 06 '17 at 19:45
  • @ochi The question is not what determines duplicate, it's the answers. The answers there address this. – user1803551 Dec 06 '17 at 19:49
  • @user1803551 I'll agree to disagree ;) – blurfus Dec 06 '17 at 19:51
  • IMO this is a reasonable question - it's asking how to model where and when an iterator points (i.e. is it pointing "in between", "before", or something else?) – Oliver Charlesworth Dec 06 '17 at 19:59
  • 3
    It's all about the documentation as it just says *"returns the next element"*. Technically *next* implies that there was already something before. So in my opinion it is reasonable to ask what the first element is. The documentation could have explained this better. – Zabuzard Dec 06 '17 at 20:07
  • @OliverCharlesworth And that is shown well in the [tutorial](https://docs.oracle.com/javase/tutorial/collections/interfaces/list.html), with a diagram, code examples and explanation. Questions which do not do research are not good questions and this is even a good downvote reason. – user1803551 Dec 06 '17 at 20:09
  • @user1803551 - Point taken. But bear in mind that's a tutorial page for `List`, so not necessarily what you'd stumble upon if you're researching the semantics of iterators in general. And as Zabuza points out, the language in the Javadoc isn't necessarily helpful. – Oliver Charlesworth Dec 06 '17 at 20:12
  • @ochi Maybe you'd prefer https://stackoverflow.com/questions/26194702/cursor-implementation-in-iterator-in-java-collections – user1803551 Dec 06 '17 at 20:16

4 Answers4

7

Think of next as a two-step process. First it gets the next item in the iterator, then it increments the pointer to point to the next item. So, when you create a new iterator, it is initialized to return the first item (index 0) in your list.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
5

My way to imagine the way iterators work is to think about it as the thing that is placed between the indexes. So when the first next() is being called you can return the value stored under the [0] index and after that call, iterator waits between index [0] and [1] for the next call to return for you value stored at index [1]. After the second next() call iterator waits between [1] and [2] and so on...

It is just my way to get used to iterators but it might be helpful for you some way.

Przemysław Moskal
  • 3,551
  • 2
  • 12
  • 21
2

The code you show will correctly print all elements of the ArrayList. The it.next() call will, at its first call, also the first element. This element is usually denoted with index 0.

Note that you might want to rename arrayOfStrings as technically it's no array, it's more a List. A user might due the name think that it is an array.


Documentation

In my opinion you are right that the documentation of the method can be a bit confusing since it is so compact:

Returns the next element in the iteration.

However the description probably needs to be so undetailed since Iterator is a very frequently used interface, not only for collections. I could imagine a class where the first iteration element should not be the first element of the underlying structure. For example some kind of stream that was already read until a given point. So basically it is up to the implementing class to decide what the first element is. But for collections it will truly be the first element (index 0).


For-each

Also note that the iteration you show is equivalent to how the extended for-loop (for-each) works in Java. So a syntax like

for (Item item : items) {
    ...
}

will be treated like

Iterator<Item> iter = items.iterator();
while(iter.hasNext()) {
    Item item = iter.next();
    ...
}

In fact this is the reason why you can use everything that implements Iterable in extended for loops.

Knowing this it would rather be confusing if iter.next() would skip the first element. I mean by the name for-each is supposed to iterate all elements.


Insights

Let's take a closer look at how the method is implemented. Therefore we will first see what ArrayList#iterator does. Take a look at its source code:

public Iterator<E> iterator() {
    return new Itr();
}

The Itr class is a private class of ArrayList (source code). And here is the Itr#next method:

@SuppressWarnings("unchecked")
public E next() {
    checkForComodification();
    int i = cursor;
    if (i >= size)
        throw new NoSuchElementException();

    Object[] elementData = ArrayList.this.elementData;
    if (i >= elementData.length)
        throw new ConcurrentModificationException();

    cursor = i + 1;
    return (E) elementData[lastRet = i];
}

So what it essentially returns is the element at index i which is where the cursor was at the point of calling the method. It also already advances the cursor by one for the next call of the method.

The cursor however is implicitly initialized with 0 due to:

int cursor; // Default value for int is 0

So the first call of next will indeed return the element at index 0 which is the first element.

Zabuzard
  • 25,064
  • 8
  • 58
  • 82
  • Thank you for the very detailed answer. But I can't see from the `Itr#next`method code you provided here where the cursor and size parameters are coming from? How these parameters are passed here? – Prophet Oct 23 '19 at 20:19
  • 1
    The iterator comes from the arraylist, it remembers the current index as field internally. – Zabuzard Oct 24 '19 at 06:56
0

I will explain this with ListIterator which has both next and previous. next has same concept in both Iterator and ListIterator

ListIterator<String> itr = linkedList.listIterator();

Here itr will point at first index (index=0)

Think next as "current" and previous as "previous".

That means,

itr.hasNext() = returns true if itr has any element at current position.

itr.next() = return the current element and move itr to next position.

itr.hasPrevious() = returns true if there is any element at position before itr.

itr.previous() = move the itr to previous element and return that element.