views:

740

answers:

11

Hi,

Personally, I find the range of functionality provided by java.util.Iterator to be fairly pathetic. At a minimum, I'd like to have methods such as:

  • peek() returns next element without moving the iterator forward
  • previous() returns the previous element

Though there are lots of other possibilities such as first() and last().

Does anyone know if such a 3rd party iterator exists? It would probably need to be implemented as a decorator of java.util.Iterator so that it can work with the existing java collections. Ideally, it should be "generics aware".

Thanks in advance, Don

+3  A: 

You can get previous() easily by just using a java.util.ListIterator.

Peek at that point is easily implemented by doing a

public <T> T peek(ListIterator<T> iter) {
    T obj = iter.next();
    iter.previous();
    return obj;
}

Unfortunately it will be easier to have it as a utility method since each collection class implements their own iterators. To do a wrapper to get a peek method on each collection on some interface such as MyListIterator would be quite a lot of work.

William
+5  A: 

I think the reason these aren't implemented is because they are non-trivial for some collections and would have large performance impact. I think it would be pretty simple for you to make this work for the collections you care about.

I also don't like that Java iterators have no way of getting the current value without moving it (and therefore you can't easily write code that branches based on the value, just passing the iterator -- you have to pass the value you now have as well).

Lou Franco
A: 

I haven't ever run into an issue where I've needed a peek(); Iterator has worked just fine for me. I'm curious how you're using iterators that you feel you need this added functionality.

Steve g
I think the most common case is some kind of dispatch. You want to read the first element to see who should handle it and dispatch -- if the receiver needs the whole sequence it's nice to just pass that and not have to also pass the removed object.
Lou Franco
I can see that. It just has the smell to it of something that could be done much easier some other way like a visitor or something.
Steve g
+3  A: 

One thing I would look at is the Seq implementation in clojure

http://clojure.org/sequences

The implementation of the base classes are in Java and full source is available. Seqs are decorators on java iterators (take and implement java iterator interfaces) -- but they also provide their own interface which might be more of what you want -- or at least a starting point.

Lou Franco
+4  A: 

Apache Commons Collections

Google Collections

ykaganovich
Thanks, but AFAIK the Apache commons collections *still* has not been generified
Don
A: 

It sounds like you might be better off using a Stack.

Draemon
+3  A: 

There is a good damn reason the generic operators do not implement these features: they do not exist for all container. The typical example is a container representing some external data input, like a file seen as a stream. Each time you read a value you consume it and move the pointer forward, if you want it or not. If you impose these constraints on the generic iterators, then you loose the genericity of the iterators.

If you want a previous method, as suggested, use the ListIterator<>, which is then restricted to container behaving as lists.

PierreBdR
+1  A: 

As ykaganovich suggested, you might want to check out the google-collections stuff. There is definitely some support for some of the things you want, like peeking. Also, as some others have mentioned, implementing all of these things for all collections can be dangerous from a possibility or performance viewpoint.

Paul Wicks
A: 

The Java collections were written to provide a minimal set of useful functionality. This is a very good approach for code that has to be implemented by anyone implementing Java. Bloating an interface with functionality that might be useful can lead to a sizable increase in volume of code with improvements noticed only by a few. If peek() and previous() were part of the standard iterator that means everyone writing a new kind of Collection must implement it, whether it's sensible or not.

Iterators are also designed to work on things that physically cannot go backwards, making peek() and previous() both impossible.

DJClayworth
+1  A: 
public class Iterazor<T> {
  private Iterator<T> it;
  public T top;
  public Iterazor(Collection<T> co) {
    this.it = co.iterator(); 
    top = it.hasNext()? it.next(): null; 
  }
  public void advance() { 
    top = it.hasNext()? it.next(): null; 
  }
}

// usage

for(Iterazor<MyObject> iz = new Iterazor<MyObject>(MyCollection); 
    iz.top!=null; iz.advance())
  iz.top.doStuff();
}
A: 

I saw that someone linked to Google Collections, but no one mentioned that the method you are looking for is called Iterators.peekingIterator().

Still, it would be best if you could just use a ListIterator.

Kevin Bourrillion