A follow-on, rags-to-riches implementation of The most efficient way to merge two lists in Java
The original requirements are to:
Identify the distinct values from two input files, and output the distinct values to an output file. There is no specification for the order of the output, only that each line should be unique in the results.
Special consideration should be made for efficiency.
I have implemented a more general specification:
- merge multiple input files (at least one) to an output file
- each line is treated as a line, not necessarily a "word". If the input files have just one word per line, then the output would be the same as the original specification.
- take the input files from the commandline (the first file is the output file).
In my answer to the linked post I suggested that a Java 8 Streams implementation would be "nice". I have implemented that solution here. I am looking for suggestions on how to better utilize the new Java functionality, and any other suggestions you may have.
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
@SuppressWarnings("javadoc")
public class Linemerge {
/* Wrap the IOException in order to make convenient Stream usage. */
private static final void writeWord(BufferedWriter writer, String word) {
try {
writer.write(word);
writer.newLine();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private static void merge(Path source, Set<String> seen, BufferedWriter writer) throws IOException {
try (Stream<String> words = Files.lines(source)) {
words.filter(seen::add).forEach(word -> writeWord(writer, word));
}
}
public static void main(String[] args) {
if (args.length < 2) {
throw new IllegalArgumentException("Need at least two file arguments: Destination Source {Source {Source {...}}}");
}
Path dest = Paths.get(args[0]);
try (BufferedWriter writer = Files.newBufferedWriter(dest)) {
Set<String> seen = new HashSet<>();
for (int i = 1; i < args.length; i++) {
Path source = Paths.get(args[i]);
if (Files.isRegularFile(source) && Files.isReadable(source)) {
System.out.println("Merging " + source);
merge(source, seen, writer);
} else {
System.out.println("Unable to read (and ignoring) " + source);
}
}
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
}