Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enhanced for-loop does not accept Iterator

Excuse me if this has been asked before. My search did not bring up any other similar question. This is something that surprised me in Java.

Apparently, the enhanced for-loop only accepts an array or an instance of java.lang.Iterable. It does not accept a java.util.Iterator as a valid obj reference to iterate over. For example, Eclipse shows an error message for the following code. It says: "Can only iterate over an array or an instance of java.lang.Iterable"

Set<String> mySet = new HashSet<String>();
mySet.add("dummy");
mySet.add("test");
Iterator<String> strings = mySet.iterator();
for (String str : strings) {
    // Process str value ...
}

Why would this be so? I want to know why the enhanced for-loop was designed to work this way. Although an Iterator is not a collection, it can be used to return one element at a time from a collection. Note that the only method in the java.lang.Iterable interface is Iterator<T> iterator() which returns an Iterator. Here, I am directly handing it an Iterator. I know that hasNext() and next() can be used but using the enhanced for-loop makes it look cleaner.

One thing I understand now is that I could use the enhanced for-loop directly over mySet. So I don't even need the extra call to get an Iterator. So, that would be the way to code this, and yes - it does make some sense.

like image 281
Ajoy Bhatia Avatar asked Jul 10 '15 18:07

Ajoy Bhatia


3 Answers

The enhanced for loop was part of JSR 201. From that page, you can download the proposed final draft documents, which include a FAQ section directly addressing your question:

Appendix I. Design FAQ

  1. Why can't I use the enhanced for statement with an Iterator (rather than an Iterable or array)?

Two reasons: (1) The construct would not provide much in the way on syntactic improvement if you had an explicit iterator in your code, and (2) Execution of the loop would have the "side effect" of advancing (and typically exhausting) the iterator. In other words, the enhanced for statement provides a simple, elegant, solution for the common case of iterating over a collection or array, and does not attempt to address more complicated cases, which are better addressed with the traditional for statement.

  1. Why can't I use the enhanced for statement to:
    • remove elements as I traverse a collection ("filtering")?
    • simultaneously iterate over multiple collections or arrays?
    • modify the current slot in an array or list?

See Item 1 above. The expert group considered these cases, but opted for a simple, clean extension that dose(sic) one thing well. The design obeys the "80-20 rule" (it handles 80% of the cases with 20% of the effort). If a case falls into the other 20%, you can always use an explicit iterator or index as you've done in the past.

In other words, the committee chose to limit the scope of the proposal, and some features that one could imagine being part of the proposal didn't make the cut.

like image 157
Kenster Avatar answered Nov 16 '22 05:11

Kenster


The enhanced for loop was introduced in Java 5 as a simpler way to iterate through all the elements of a Collection [or an array].

http://www.cis.upenn.edu/~matuszek/General/JavaSyntax/enhanced-for-loops.html

An iterator is not a collection of elements,

it is an object that enables a programmer to traverse a container. An iterator may be thought of as a type of pointer.

https://en.wikipedia.org/wiki/Iterator

So enhanced for loops work by going through all the elements in a structure that contains elements, while an iterator doesn't contain elements, it acts more like a pointer.

like image 36
Olivier Poulin Avatar answered Nov 16 '22 07:11

Olivier Poulin


In your example, you are creating an iterator but not using it properly. As to answer your question of why the exception is being thrown- it's from the line:

 for (String str : strings) {

"strings" is an iterator here, not a collection that you can iterate through. So you have a few options you can iterate through the set by using an enhanced for loop:

for(String myString : mySet){
    //do work
}

or you can iterate through the set using an iterator:

Iterator<String> strings = mySet.iterator();
while(strings.hasNext()){
    //do work
}

hope you find this helpful.

like image 1
GregH Avatar answered Nov 16 '22 07:11

GregH