Composable heavy-weight iterators for Java.
An IOStream
provides hasNext
and next
methods, just like an Iterator
, but is also Closeable
and throws predictable checked exceptions.
Like Iterable
, IOStreamable
types can provide fresh instances of IOStream
to provide sequential access to a resource.
Utility methods on IOStreams
and IOStreamables
allow streams to be transformed and composed.
IOStreams is provided under the Apache License Version 2.0.
This example uses IOStreams to lazily read the given text files and output their contents line-by-line.
public static void main(final String... args) throws IOStreamException, InterruptedException
{
// Start with a list of file names
IOStreams.fromArray(args)
// Read each line from each file
.flatMap(file -> FileLineIOStream.fromFile(Paths.get(file), StandardCharsets.UTF_8))
// Filter out empty lines or lines that start with a comment
.skip(line -> line.text.matches("\\s*(#.*)?"))
// Prefix with the path and line number, and trim whitespace and comments from the lines that are left
.map(line -> line.path + "\t" + line.number + "\t" + line.text.replaceAll("^\\s+|\\s*#.*$", ""))
// Consume each file by printing uncommented lines to standard out.
.consume(System.out::println);
}
Why not just write a couple of loops?
Sure, let's have a look at that version.
public static void main(final String... args) throws IOException, InterruptedException{
// Start with a list of file names
for(String file : args){
// Read each line from each file
try(final BufferedReader reader = Files.newBufferedReader(Paths.get(file), StandardCharsets.UTF_8)){
int lineNumber = 0;
for(String lineText = reader.readLine(); lineText != null; lineText = reader.readLine(), lineNumber++){
if(Thread.interrupted()) throw new InterruptedException();
// Filter out empty lines or lines that start with a comment
if(lineText.matches("\\s*(#.*)?")) {
// Prefix with the path and line number, and trim whitespace and comments from the lines that are left
String result = file + "\t" + lineNumber + "\t" + lineText.replaceAll("^\\s+|\\s*#.*$", "");
// Consume each file by printing uncommented lines to standard out
System.out.println(result)
}
}
}
}
}
It's just as concise, and doesn't use any libraries. If this is all you need, use this instead. But! Notice that there are three nested bits of logic here:
- Opening and closing files
- Filtering and transforming lines of text
- Displaying results
In the IOStreams example, these are all independent - you could swap out the call to System.out.println
with something that writes results to another file, without changing the reading or filtering code at all. IOStreams allows you to better encapsulate and modularise your data processing code.
IOStreams is available in Maven Central.
<dependency>
<groupId>au.id.ajlane.iostreams</groupId>
<artifactId>iostreams</artifactId>
<version>0.0.9</version>
</dependency>