15

Yesterday, when I was answering to question getting ConcurrentModificationException error while using iterator and remove I added a notice that

It's not a good idea to use iterators when you have ArrayLists.

You do not need to deeply understand that question to answer on that one.

There, I got two comments that I'm wrong.

My arguments:

  1. The code is much less readable with iterators.

  2. There is a possibility to raise ConcurrentModificationException that is hard to debug.

Can you please explain?

Question: Do we ever need to explicitly use Iterators on ArrayList?

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
Vitaly
  • 2,760
  • 2
  • 19
  • 26

6 Answers6

27

A big use case of iterators with ArrayLists is when you want to remove elements while iterating. You have only three safe solutions:

  • use an iterator and its remove method
  • copy the elements you want to keep to another list
  • juggle with indexes

Assuming you don't add while iterating, using the iterator is a means to avoid the ConcurrentModificationException.

The readability argument is subjective. Personally I don't find a cleanly declared iterator less readable. And it doesn't really matter as the iterator is the safe way to iterate and remove at the same time.

fig
  • 732
  • 1
  • 8
  • 14
Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • 1
    The only good looking reason for me: "use an iterator and its remove method". If someone just wants to iterate and remove unneeded items from the list. Thanks. – Vitaly Apr 09 '13 at 23:33
  • @dystroy sorry to open this up, but i don't understand why you need to use an Iterator to remove an element from the ArrayList? – 12rad Jul 30 '13 at 21:19
  • @Vitaly I did a quick test List a = new ArrayList(); a.add("a"); a.add("b"); a.add("c"); a.add("d"); a.add("e"); a.remove("b"); and it seems to work. – 12rad Jul 30 '13 at 21:19
  • 1
    @12rad If you loop over an arraylist, either directly or using an iterator, and at the same time you remove elements from the arraylist, you'll have problems (errors or a ConcurrentModificationException) if you don't use the specific remove method of the iterator. – Denys Séguret Jul 31 '13 at 06:42
  • @dystroy i see, so, it's only when i i'm actually looping through. But if i just add elements and then remove one by a.remove("b), it's safe? -------- Like:List a = new ArrayList(); a.add("a"); a.add("b"); a.add("c"); a.add("d"); a.add("e"); a.remove("b"); – 12rad Jul 31 '13 at 21:38
16

None of the answers seem to adres the reason for iterators. The iterator design pattern was created because an object should be in control of its own state ( except maybe value objects with only public properties ).

Lets say we have an object that contains an array, and you have an interface in that object to add items to that array. But you have do something like this:

class MyClass
{
    private ArrayList<Item> myList;

    public MyClass()
    {
        myList = new ArrayList();
    }

    public addItem( Item item )
    {
         item.doSomething(); // Lets say that this is very important before adding the item to the array.
         myList.add( item );
    }
}

Now if i had this method in the class above:

public ArrayList getList()
{
    return myList;
}

Somebody could get the reference to myList through this method and add items to the array, without calling item.doSomething(); That's why you shouldn't return a reference to the array, but instead return its iterator. One can get any item from the array, but it can't manipulate the original array. So the MyClass object is still in control of it's own state.

This is the real reason why iterators were invented.

David
  • 1,227
  • 12
  • 23
  • I know this is old, but I'm going to comment this anyway. your statement `you shouldn't return a reference to the array, but instead return its iterator. One can get any item from the array, but it can't manipulate the original array.` holds true for the regular good old `Iterator`, however the `ListIterator` can add more elements to the original list. –  Jan 06 '21 at 21:34
2

Yes, we need. ArrayList is just an implementation of the List interface, so often your code will process a list and not even know that it's an ArrayList. Also, the new for-loop syntax uses iterators internally.

Axel
  • 13,939
  • 5
  • 50
  • 79
1

Check this post: http://www.xyzws.com/javafaq/what-is-the-advantage-of-using-an-iterator-compared-to-the-getindex-method/19

Using iterator will avoid the mistake of using get(index) on LinkedList(extremely slow). It makes sense when the implementation of list is unknown, just use iterator. Regarding ArrayList, using iterator will still achieve the closest possible performance with get(index).

So it is a good practice to use iterator for iterating in terms of performance.

0

You are probably talking about explicitly using an iterator (since the : operator is also using the iterator behind the scenes).

Say you want to have two "pointers" going over the array but the speed depends on the actual element values. How would you do this without explicitly using iterators (and without elementAt of course).

For example (pseudo code):

element1 = first element;
element2 = first element;
while(element1.hasNext && element2.hasNext)
{
    if(element1 * 2 < element)
    {
        element2 = element2.next;
    }
    else
    {
        element1 = element1.next;
    }

    //do something with the pair of elements
}
Petar Ivanov
  • 91,536
  • 11
  • 82
  • 95
  • Thanks. We can use ArrayList.elementAt(), why not? :) Could you clarify what do you mean with "the speed depends on the actual element values"? – Vitaly Apr 05 '13 at 07:47
  • @Vitaly Because then your code is `ArrayList`-specific, instead of being general to any `List.` – user207421 Apr 05 '13 at 11:40
  • It's not "my code" :) and the questions is about if we know it's ArrayList. – Vitaly Apr 05 '13 at 13:10
0

The code is much less readable with iterators.

That's entirely your opinion, and I don't share it.

There is a possibility to raise ConcurrentModificationException that is hard to debug.

That possibly exists whether you use Iterators or not. That exception tells you something useful about your code that you might otherwise miss altogether, which is even harder to debug.

Personally I prefer being able to write exactly the code as between ArrayList and LinkedList, and having the compiler or the API implement the details.

The moral is that you shouldn't pass off your own unsupported opinion as established fact.

user207421
  • 305,947
  • 44
  • 307
  • 483