Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any way for reading two or more files in one Java8-stream?

I like new Java8 StreamAPI and want use it not only for one file. As usually, I use this code:

Stream<String> lines = Files.lines(Paths.get("/somepathtofile"));

But how read two file in one stream if it possibly?

like image 679
mechanikos Avatar asked Apr 17 '15 05:04

mechanikos


1 Answers

Without any extra helper functions or outside libraries, the easiest is:

Stream<String> lines1 = Files.lines(Paths.get("/somepathtofile"));
Stream<String> lines2 = Files.lines(Paths.get("/somepathtoanotherfile"));

Stream.concat(lines1, lines)
    .filter(...)
    .forEach(...);

If Files.lines hadn't been declared to throw a checked exception, you'd be able to do

Stream.of("/file1", "/file2")
     .map(Paths::get)
     .flatMap(Files::lines)....

But, alas, we can't do that. There are several workarounds. One is to make your own version of Files.lines that calls the standard one, catches IOException and rethrows as an UncheckedIOException. Another approach is a more general way to make functions out of methods that throw checked exceptions. It would look something like this:

@FunctionalInterface
public interface ThrowingFunction<T,R> extends Function<T,R> {

    @Override
    public default R apply(T t) {
        try {
            return throwingApply(t);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static<T,R> Function<T,R> wrap(ThrowingFunction<T,R> f) {
        return f;
    }

    R throwingApply(T t) throws Exception;
}

and then

Stream.of("/somefile", "/someotherfile", "/yetanotherfile")
        .map(Paths::get)
        .flatMap(ThrowingFunction.wrap(Files::lines))
        .....

There are several libraries out there that went through the trouble of writing something like the above out for every functional interface.

like image 97
Misha Avatar answered Oct 28 '22 04:10

Misha