Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do you have to recompute java Stream<T> every time?

I wrote this method:

public static void main(String... args) {
    try (var linesStream = Files.lines(Paths.get("C:\\Users\\paul\\Desktop\\java.txt"))) {
        Stream<String> words = linesStream.
                flatMap(line -> Arrays.stream(line.split(" ")))
                .distinct();
        System.out.println("There are " + words.count() + " distinct words in this file, here they are:");
        words.forEach(System.out::println);
    } catch (IOException e) {
        System.err.println(e.getMessage());
    }
}

The problems I have here is that I operate on the words Stream<String> twice. In order to do that do you have to explicitly rebuild this stream, or is there some magic reset method I could use?

Also, in order to rebuild the words stream again, I have to rebuild the linesStream and wrap that into another try/catch block here... Very verbose. What is a method to make this type of things easier to write?

I guess I could do:

    static Stream<String> getStreamFromFile() throws IOException {
        return Files.lines(Paths.get("C:\\Users\\paul\\Desktop\\java.txt"));
    }

    static Stream<String> getDistinctWords(Stream<String> lines) {
        return lines
                .flatMap(line -> Arrays.stream(line.split(" ")))
                .distinct();
    }

    public static void main(String... args) {
        Stream<String> lines1 = null;
        Stream<String> lines2 = null;
        try {
            lines1 = getStreamFromFile();
            lines2 = getStreamFromFile();
            Stream<String> distinctWords1 = getDistinctWords(lines1);
            Stream<String> distinctWords2 = getDistinctWords(lines2);
            System.out.println("There are " + distinctWords1.count() + " distinct words in this file, here they are:");
            distinctWords2.forEach(System.out::println);
        } catch (IOException e) {
            System.err.println(e.getMessage());
        } finally {
            lines1.close();
            lines2.close();
        }
    }

but is this all I am left with?

like image 669
Coder-Man Avatar asked Mar 07 '26 14:03

Coder-Man


2 Answers

You can't re-use streams. Just collect the elements into a collection, e.g. a List, or call a (stateful) function which outputs each element and also increments a count.

like image 187
jon-hanson Avatar answered Mar 10 '26 03:03

jon-hanson


You can't reset a Stream, but you can collect the results of your distinct(); and you can also use \\s+ as a regex. Like,

static List<String> getDistinctWords(Stream<String> lines) {
    return lines.flatMap(line -> Arrays.stream(line.split("\\s+"))).distinct()
            .collect(Collectors.toList());
}

And then change your caller like

List<String> distinctWords = getDistinctWords(lines);
System.out.println("There are " + distinctWords.size() 
        + " distinct words in this file, here they are:");
distinctWords.forEach(System.out::println);

And you shouldn't hard code paths like that, you can use the user.home system property to locate your file. Like,

return Files.lines(Paths.get(System.getProperty("user.home"), "Desktop/java.txt"));
like image 35
Elliott Frisch Avatar answered Mar 10 '26 02:03

Elliott Frisch