Merging word streams from files 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&lt;String&gt; seen, BufferedWriter writer) throws IOException {
        try (Stream&lt;String&gt; words = Files.lines(source)) {
            words.filter(seen::add).forEach(word -&gt; writeWord(writer, word));
        }
    }

    public static void main(String[] args) {
        if (args.length &lt; 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&lt;String&gt; seen = new HashSet&lt;&gt;();
            for (int i = 1; i &lt; args.length; i++) {
               Path source = Paths.get(args[i]);
               if (Files.isRegularFile(source) &amp;&amp; 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);
        }
    }

}
"Need at least two file arguments: Destination Source {Source {Source {...}}}"


I think an easier way of documenting that, at least for *nix, is:

"Need at least two file arguments: DESTINATION [SOURCE]..."


You can also turn the Paths in your main() method into a Stream too:

public class Linemerge {
    // ...

    // suggestion note: had to wrap IOException -&gt; UncheckedIOException too
    private static void merge(Path source, Set&lt;String&gt; seen, BufferedWriter writer) {
        try (Stream&lt;String&gt; words = Files.lines(source)) {
            words.filter(seen::add).forEach(word -&gt; writeWord(writer, word));
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    private static final Predicate&lt;Path&gt; FILTER =
            f -&gt; Files.isRegularFile(f) &amp;&amp; Files.isReadable(f);

    private static void checkPath(Path path) {
        System.out.println((FILTER.test(path) ? "Merging"
                : "Unable to read (and ignoring)") + " " + path);
    }

    public static void main(String[] args) {
        if (args.length &lt; 2) {
            throw new IllegalArgumentException(
                    "Need at least two file arguments: DESTINATION [SOURCE]...");
        }
        try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(args[0]))) {
            Set&lt;String&gt; seen = new HashSet&lt;&gt;();
            Stream.of(args).skip(1).map(Paths::get).peek(Linemerge::checkPath)
                    .filter(FILTER).forEach(f -&gt; merge(f, seen, writer));
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}