Granny's Programming Pearls
"inside of every large program is a small program struggling to get out"
JavaRanch.com/granny.jsp
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

what is the difference in iterating thru a ArrayList using Iterator interface or For loop  RSS feed

 
narendra nath
Ranch Hand
Posts: 33
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello Good folks,

I was able to iterate thru an arraylist using iterator as well as for loop successfully. Then what is the benefit or why should we use and iterator interface for iterating?


Thanks and regards
Nath
 
Campbell Ritchie
Marshal
Posts: 55786
164
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Look at the RandomAccess interface. ArrayList supports random access so it is as fast to find element 1000000 as the first element. Then a for loop works nicely.
 
Tushar Goel
Ranch Hand
Posts: 934
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sorry Campbell but dint understand what difference RandomAccess causes while iterating whole list. For any particular element i got your point.
 
Campbell Ritchie
Marshal
Posts: 55786
164
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
In a linked list, it takes a long time to go from element 0 to element 1000000. So the Iterator keeps a reference to element n so it only has to go one step to get to element n + 1. You should therefore not use myList.get(i) on a linked list:-… will run in quadratic time on a linked list. On an array list however (which includes Vector) there is no need to go from element 0 to element 1000000. Calling an index of an array runs in constant time and it can take as little as 1 clock cycle to find element 1000000. The above code will run at least as fast on an array list as using an Iterator. Now look at the RandomAccess interface again.
 
Stephan van Hulst
Saloon Keeper
Posts: 7820
142
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
As for what the difference between using the enhanced for loop and using the iterator directly, you would use the iterator directly if you need to modify the list as you're traversing it. Here's an example:

The following code would throw an exception:
 
Tushar Goel
Ranch Hand
Posts: 934
4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
if (shouldRemove(foo)) {
it.remove();
}


I think this one too throw concurrent-modification exception as well, as array list iterator is fail fast.
 
Campbell Ritchie
Marshal
Posts: 55786
164
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No, an Iterator is permitted to remove the “next” from a List. That ought not to throw an Exception.
 
Stephan van Hulst
Saloon Keeper
Posts: 7820
142
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No. The reason that ConcurrentModificationException is thrown is because removing an object leaves an iteration in an undefined state. Imagine the following iteration:

1 2 3 4 5 6
  ^


We remove the element. Now, what should the current iteration state be?
1 3 4 5 6
  ^


or
1 3 4 5 6
^


You may be tempted to say the first option, but the pointer hasn't advanced yet. That means that for the next step, the element 3 is skipped. You can see this is already confusing stuff for simple array lists, and it becomes even more complex when the data type may go through a huge structural change on removal of an element, for example, hash maps and trees. That's why you can't structurally change a collection while you're iterating it.

The iterator class however, *always* has a set definition for what the next element is. After you remove an element using the iterator, calling next() will return the correct element in the iteration order. It will only throw an exception if you structurally change the collection using anything else but that iterator, including another iterator.
 
narendra nath
Ranch Hand
Posts: 33
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the replies folks.

I tried Iterator on an arraylist and tried to remove an element. But I am getting "Exception in thread "main" java.util.NoSuchElementException"



 
Jason Bullers
Ranch Hand
Posts: 115
11
Clojure IntelliJ IDE Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The code as you posted it will run just fine. However, if you uncomment the print statement, then you will indeed get the exception you reported. Remember: every time you call next() on an iterator, you advance to the next element. You check if you have more elements to iterate over in the loop condition with hasNext(), and then you proceed in to the loop body. What happens if you only have one element left to iterate over before entering the loop?
 
Campbell Ritchie
Marshal
Posts: 55786
164
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
How peculiar. I tried your code, but used a Stream to create the List from the args array. I had to invoke ti like this:-
java ListRemovalDemo 1 2 69 4 3 87465 -8745 -9999999
You see it uses the same logic as yours; deleting .intValue() in line 27 made no difference. I suffered no Exceptions. That isn't quite true; if I passed -99999999999999999 as an argument I got a NumberFormatException
JB is correct; if you use next() twice in the loop you are liable to run out of List if you have an odd number of elements.

I think you can create a new List minus the 3 like this in Java8 only:-
List<Integer> listWithout3 = list.stream().filter(i != 3).collect(Collectors.toList());
 
narendra nath
Ranch Hand
Posts: 33
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks a lot.

Greatly appreciate.
 
Campbell Ritchie
Marshal
Posts: 55786
164
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You're welcome

Try the versions of the code with the Streams.

In the constructor you have a String[] which you turn into a Stream<String> with the method of the Arrays class.
Then you use the map method to create a different kind of Stream; the bit with :: in the middle means call the valueOf(String) method of the Integer class. The compiler will presume you want to pass a String to that method because you are inside a Stream of Strings. Now you have a Stream<Integer>.
Then you use the collect method which uses a Collector object to create a List. The actual Collector object is that whose reference is returned from the toList method.

Instead of using the Iterator, the second line uses the stream method, actually in the Collection interface, to create a Stream; since the List is a List<Integer> the Stream will be a Stream<Integer>. The filter() method can test whether the value is 3 or not. You want to keep everything which is not equal to 3. The compiler “knows” that it is possible to use the intValue method or unboxing, so you can use != 3. Then you turn it back to a List with exactly the same technique with toList.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!