Java pattern for reverse iterator and iterable methods?

Viewed 105

If a class implements the Iterable interface, e.g.

class Query implements Iterable<Query.Entry> {

    class Entry {
        // ...
    }

    @Override
    public Iterator<Entry> iterator() {
        return new EntryIterator();
    }   
}

then using an enhanced for is possible,

Query q;
// ...
for( Query.Entry e : q ) {
    // ...
}

but now needs to support other ways to perform iteration, e.g.

class Query implements Iterable<Query.Entry> {

    class Entry {
        // ...
    }

    @Override
    public Iterator<Entry> iterator() {
        return new EntryIterator();
    }   

    // new methods for reverse iteration
    public Iterator<Entry> reverseIterator() {
        return new ReverseEntryIterator();
    }

    public Iterable<Entry> reverseIterable() {
        return new Iterable<Entry>() {
            @Override
            public Iterator<Entry> iterator() {
                return new ReverseEntryIterator();
            }
        };
    }
}

would there be a "standard" way of doing this? The above code adds reverseIterable and reverseIterator, but looks somewhat messy. Maybe its better style to do without a reverseIterable method?

2 Answers

Another approach would be to just use iterator() itself on a reverse view of the forward order.

That would allow you to write code like this:

for( Query.Entry e : q.reverse() ) {
   // ...
} 

If you already have a List representation, implementing the reverse() function can be easy, either with the O(n) java.util.Collections.reverse(List) or Guava's O(1) com.google.common.collect.Lists.reverse(List).

You can omit the definition of the ReverseEntryIterator class by using an anonymous inner class.

Since Iterable is a functional interface that only defines the iterator() method, reverseIterable() can be defined as a method that returns a lambda expression.

// new methods for reverse iteration
public Iterator<Entry> reverseIterator() {
    return new Iterator<Entry>() {

        @Override
        public boolean hasNext() {
            // ...
        }

        @Override
        public Entry next() {
            // ...
        }
    };
}

public Iterable<Entry> reverseIterable() {
    return () -> reverseIterator();
}
Related