Thursday, August 26, 2010

More uses for Iterables

Iterable is one of my favorite interfaces in Java. I love the for-each construct:

for (final Type item : iterableOfItems)
    doSomethingWith(item);

Notice what cannot go wrong:

  1. I cannot run off the end, or forget to go far enough (no off-by-one bugs)
  2. I cannot forget to call hasNext() before calling next() (iterator misuse)
  3. I cannot make the wrong cast or pick the wrong container type

I could go on. It is also concise and conveys programmer intention clearly, both wonderful virtues.

How can I make more use of Iterable?

Here is an example of transforming input into Iterable. First the base class:

public abstract class ResourceIterable<T, R extends Closeable>
        implements Closeable, Iterable<T> {
    private final R resource;

    private volatile boolean closed;

    protected ResourceIterable(final R resource) {
        this.resource = resource;
    }

    protected final R resource() {
        return resource;
    }

    protected abstract T getNext()
            throws IOException;

    @Override
    public final void close()
            throws IOException {
        closed = true;
        resource.close();
    }

    @Override
    public final Iterator<T> iterator() {
        return new Iterator<T>() {
            private T next;

            @Override
            public boolean hasNext() {
                try {
                    next = getNext();
                    return null != next;
                } catch (final EOFException ignored) {
                    next = null;
                    return false;
                } catch (final IOException e) {
                    next = null;
                    if (closed)
                        return false;
                    throw new UndeclaredThrowableException(e);
                }
            }

            @Override
            public T next() {
                if (null == next)
                    throw new NoSuchElementException();
                return next;
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }
}

And a sample using class:

public class LineIterable
        extends ResourceIterable {
    public AmpsResponseIterable(final BufferedReader reader) {
        super(reader);
    }

    @Override
    protected String getNext()
            throws IOException {
        return resource().readLine();
    }
}

The example is trivial (my actual uses are hiding sophisticated readers of data structures from network connections) but clear:

for (final String line : new LineIterable(someBufferedReader))
    process(line);

However, all use of Iterable is similarly trivial: that's the point if it. The complexity is in extracting objects from the input (though not in this example).

I prefer hard-to-write-easy-to-use code when I make libraries; easy-to-write-hard-to-use just feels lazy (the wrong kind of lazy).

Post a Comment