views:

984

answers:

9

I'm trying to replace an iterator-based loop over a Java list with a for-each statement, but the code uses at some point iterator.hasNext() to check if it reached the last element in the list.

Is there something similar for the for-each alternative?

for (Object current : objectList) {
   if (last-element) 
      do-something-special
}
+10  A: 

for-each is just syntactic sugar for iterator version and if you check compiled bytecode, then you'll notice that compilator actually change it into iterator version.

With a for-each form you can't check whether you'll have more elements or not. Just stay with explicit iterator use if you need that feature.

Luno
.. or if you need the Iterator#remove() method (if it's implemented on the actual Iterator)
Andreas_D
... or if you need to know the current index of an array you are iterating over
matt b
... that last part only being meaningful when it's a List or array; otherwise you need to create and increment a separate i anyway, so you may as well keep using the foreach loop.
Kevin Bourrillion
A: 

Read here

(The compiler does this for you behind your back, but you need not concern yourself with it.)

Bozho
I don't think this answers the question ...
Joachim Sauer
it explains why using for-each and iterator is the same thing.
Bozho
A: 

If you want to stay with for-each maybe something like this:

if (objectList.indexOf(current)==objectList.size()-1) break;
PeterMmm
That can be quite expensive for large lists.
Jorn
We can iterate (with for-each) through any class that implements Iterable interface, it doesn't hae to be a list and it ofc doesn't have to provide any indexOf method
Luno
+1  A: 

Unfortunately, the for each idiom does not allow you to check if an element is first or last in the list. This is a known limitation of the for each loop. I suggest you just keep using the iterator.

If you can also check for the first element instead of the last one, for example if you're doing String concatenation, you could change to something like:

boolean first = true;
for (Element e : list) {
  if (!first) {
    //do optional operation
  }
  //do other stuff
  first = false;
}

but I would prefer using the iterator.

Jorn
A: 
int nElts = objectList.size();
int n = 0;
for (...) {
  if (++n == nElts) ...

is the best I can think of.

Carl Smotricz
Is that better than just using an explicit Iterator in the for loop though? I'd argue it's more verbose, less obvious what's going on and has a higher chance of logic errors than `if !iter.hasNext()`.
Andrzej Doyle
No, I agree it's a horrible solution. I'd retract it but I'll leave it here as a warning to others.
Carl Smotricz
Another problem here is that you assume that you've got a Collection (i.e. you have a size() method) and that it isn't expensive to call it. You can have a general Iterable object that doesn't provide a size() method. In that way the Iterator is the only way to go.
Joachim Sauer
+1  A: 

The foreach loop (or enhanced for loop) does not have facilities to keep track of which element is being iterated on at the moment. There is no way to find out which index of a Collection is being worked on, or whether there are more elements to be processed in an Iterable.

That said, one workaround that would work is to keep a reference to the object which is being iterated on at the moment in the foreach loop.

By keeping a reference of what it being worked on at the current iteration, one would be able to keep the reference once the foreach loop ends, and what is left in the variable will be the last element.

This workaround will only work if-and-only-if the last element is the only element which is needed.

For example:

String lastString = null;

for (String s : new String[] {"a", "b", "c"}) {
 // Do something.

 // Keep the reference to the current object being iterated on.
 lastString = s;
}

System.out.println(lastString);

Output:

c
coobird
+2  A: 

In addition to Luno's answer:

Iterator<MyClass> it = myCollection.iterator();
while(it.hasNext()) {
  MyClass myClass = it.next():
  // do something with myClass
}

translates to:

for (MyClass myClass:myCollection) {
  // do something with myClass
}
Andreas_D
+3  A: 

As others have said - this isn't possible.

Just remember that the foreach construct isn't the be-all and end-all. It was introduced to make the very common task of performing the same operations on each element of a collection simpler to denote.

In your case, you don't want to do exactly the same thing to each element - and thus a foreach loop is not the right tool for the job. Trying to "hack" it into doing this is silly, just use an explicit iterator in a classic for loop.

Andrzej Doyle
A: 

There are two possible cases where you would like to do this.

    You need to do something after the last element has been reached: in this case you just need to put your code outside of the loop.
    
        for(Object item:theLinkedList){
    
        }
        System.out.println("something special")
    
    you need to modify the last element in some way or use information related to the last element. In this case you should use the **LinkedList** to access the last element

    for(Object item:theLinkedList){

    }
    Object last=theLinkedList.getLast();
    System.out.println("last");
Monachus