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