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:
- I cannot run off the end, or forget to go far enough (no off-by-one bugs)
- I cannot forget to call
hasNext()
before callingnext()
(iterator misuse) - 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).
1 comment:
Nice one! I'm a big fan of Iterable too. It's a code duplication killer.
Post a Comment