tags:

views:

283

answers:

5

If we do the following we get error:

class FGH{
public static Iterator reverse(List list) {
     Collections.reverse(list);
     return  list.iterator();
     }
     public static void main(String[] args) {
     List list = new ArrayList();
     list.add("1"); list.add("2"); list.add("3");
     /*for(Iterator it:reverse(list))
     Iterator it=reverse(list);*/
     for (Object obj: reverse(list))
     System.out.print(obj + ", ");}}

but if we modify the code like this we don't get error,so is it mean that we can't iterate the objects of Iterator type? :

class FGH{
public static Iterator reverse(List list) {
     Collections.reverse(list);
     return  list.iterator();
     }
     public static void main(String[] args) {
     List list = new ArrayList();
     list.add("1"); list.add("2"); list.add("3");
     Iterator it=reverse(list);
     while(it.hasNext()){
    Object obj=it.next();
    System.out.println(obj);
     }
     }}
+5  A: 

The for loop in your first example expects that reverse(list) is a collection of Iterator, which of course it isn't. That's why that example won't work.

In general, you can only use foreach on classes that implement Iterable. Iterator is not one of these classes.

See http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Iterable.html

danben
A: 

You'd use the enhanced for loop in this way:

for (Object o : list)
JRL
+2  A: 

A lot of answers talk about how iterators are not iterables. That's true, but such an answer doesn't touch on why.

The reason for-each loops require an iterable is to allow the same object to be traversed multiple times (so that you can use multiple for-each loops over the same object without surprising behaviour), whereas an iterator only allows one traversal. If for-each allowed iterators to be used, the behaviour would be surprising to programmers who didn't realise that their iterators would be exhausted after the loop is run.

If you're using an API that only gives you iterators, and you want to use iterables, you have two ways to solve this:

  1. Make an anonymous iterable class, whose iterator() method calls the API function that returns the iterator. That way, each time you use a for-each loop on the iterable object, that API function is called again, returning a new (and unexhausted) iterator.
  2. Make a one-pass iterable wrapper class that takes an iterator and allows one call to iterator(). On subsequent calls, throw an AssertionError or IllegalStateException as appropriate.
Chris Jester-Young
Not sure what you're saying there - how could you traverse an iterable multiple times within a for-each loop? Or did I misinterpret your answer?
danben
No, I'm saying that you cannot have multiple for-each loops that all refer to the same iterator object; it'd have been exhausted (even if only partially, if the loop has a `break` or the like) after the first for-each loop.
Chris Jester-Young
An IterableIterator wrapper is a solid solution (it's actually a core part of our utilities jar used in all of our projects). I suspect another reason they didn't make Iterator extend Iterable is b/c Iterator is an interface, and extending it at this point would break a ton of existing code, or force yet another Iterator-like interface (remember Enumeration?).
Kevin Day
@Kevin: Out of curiosity, does your wrapper also enforce the one-use constraint, or otherwise document that such a wrapper can only be iterated through once? [continues]
Chris Jester-Young
[continued] At work, we have an implementation that goes to some pain to ensure this (with unit tests to enforce this one-use quality): the wrapper class keeps a static set of (weak references to) objects it's already seen, and throws if you try to create a wrapper with an already-seen object; also, the wrapper itself has a `used` flag, ensuring that `iterator()` can only be called once.
Chris Jester-Young
Chris - wow - that's a lot of overhead. No, we don't enforce single use, but usage is highly localized and we've never (and I mean *never* had a problem). If your library has risk of being misused, it might be advisable to do your checking in an assert() statement so it can at least be turned off at deployment. I'd imagine that your static cache becomes a huge concurrency contention point.
Kevin Day
PS - the way I look at this is that the IterableIterator is just a proxy for the Iterator itself to make it easier to use in a for loop. You wouldn't try to make sure that iterator.next() is only called in one place, so why go through all the trouble with what is essentially a proxy to iterator.next()? Detection of multiple usage of an iterator should probably be left to Lint (or some other static QA check), instead of a (potentially expensive) runtime check. Cheerio!
Kevin Day
@Kevin: We use Google Collections' `MapMaker` to construct the uniqueness set, with weak keys. As you may or may not be aware, this is a customised version of `ConcurrentHashMap`, so the contention is very low. I very much doubt that it's "a lot of overhead".
Chris Jester-Young
Also, there is no proxy on `next`, only on `Iterable.iterator`. Once the for-each loop gets the iterator, it has the raw iterator from that point on.
Chris Jester-Young
A: 

As pointed out above, you need to reference an Iterable (or array) in a for-each block. For example, when you do the following:

Collection<String> coll = ...;
for (String str : coll) {
    ...
}

The following is really happening:

Collection<String> coll = ...;
for (Iterator<String> iter = coll.iterator(); iter.hasNext(); ) {
    String str = iter.next();
}

In order to be able to do this, the argument has to implement Iterable (e.g. have a public iterator() method that returns an Iterator (or be an array). So your code should look like the following:

class FGH {
  public static void main(String[] args) {
     List list = new ArrayList();
     list.add("1"); list.add("2"); list.add("3");
     while (Object obj : Collections.reverse(list)){
       System.out.println(obj);
     }
  }
}
David Grant
A: 

void main() { int a,sum; for (a=1;a,=100;b=a+2;) { sum=0; sum=sum+a;

printf("%n,sum); getch(); } } why we use { for (a=1;a,=100;b=a+2;)

iqbal