How to wrap a java.util.Iterator to change the type of object being iterated

4.3k views Asked by At

I am providing some facade classes for a third-party API and I need to wrap an iterator so that I can replace what is iterated with my own facade object.

Here's a simplified version of my facade class that wraps an API class called Item

class FacadeItem {
    Item item;
    FacadeItem(Item item) {
        this.item = item;
    }
}

The API provides an iterator of this form Iterator<Item>

I need to implement an iterator of this form Iterator<FacadeItem> that is backed by the iterator of the API.

I considered using the ForwardingIterator from the Guava library as follows:

class FacadeItemIterator<FacadeItem> extends ForwardingIterator<Item> {

    final Iterator<Item> delegate; // backing iterator

    FacadeItemIterator(Iterator<Item> delegate) {
        this.delegate = delegate;
    }

    @Override protected Iterator<Item> delegate() {
        return delegate;
    }

    @Override
    public FacadeItem next() {
        return new FacadeItem(super.next());
    }
}

but the Override of next() is not permitted by the compiler because it is expecting the returned type to be Item, not FacadeItem

1

There are 1 answers

1
yshavit On BEST ANSWER

The Iterator interface isn't that big, so you could just write your own delegating iterator:

class FacadeIterator implements Iterator<FacadeItem> {
    private final Iterator<Item> delegate; // set in ctor

    @Override
    public FacadeItem next() {
        return new FacadeItem(delegate.next());
    }

    // the other two methods just delegate straight
}

and then

Iterator<FacadeItem> facadeIterator = new FacadeIterator(itemIterator);

If you're using Guava, you can use their Iterators.transform static method to make one of these for you:

Iterator<FacadeItem> facadeIterator = Iterators.transform(itemIterator,
    /* anon class of Function<Item, FacadeItem> */);

And in Java 1.8, this option becomes really easy:

Iterator<FacadeItem> facadeIterator
    = Iterators.transform(itemIterator, FacadeItem::new)