Part 17 in a Series.
I really like the Java Collections API. So much so, that I use 'em when I'm doing work that isn't particularly collectioney. For example, I recently wrote a quick-n-dirty app that rewrote some files line-by-line. Instead of using a Reader
as input, I used an Iterator<String>
. The easiest way to create such an iterator is to load the entire file into memory first.
Before:
public Iterator<String> linesIterator(Reader reader) {
BufferedReader buffered = new BufferedReader(reader);
List<String> lines = new ArrayList<String>();
try {
for (String line; (line = buffered.readLine()) != null; ) {
lines.add(line);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return lines.iterator();
}`</pre>That code is simple, but inefficient. And it won't work if the file doesn't fit into memory. A better approach is to implement `Iterator` and to read through the file on-demand as the lines are requested. Google Collections ' [AbstractIterator](http://google-collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/AbstractIterator.html) makes this easy. Whenever a new line is requested, it gets called back to read it from the stream.
### After:
<pre class="prettyprint">` public Iterator<String> linesIterator(Reader reader) {
final BufferedReader buffered = new BufferedReader(reader);
return new AbstractIterator<String>() {
protected String computeNext() {
try {
String line = buffered.readLine();
return line != null ? line : endOfData();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
}
This class is really takes the fuss out of custom iterators. Now it's not difficult to create iterators that compute a series, process a data stream, or even compose other iterators.