你每次都要重新计算java Stream <t>吗?

时间:2018-05-27 17:55:55

标签: java java-8 java-stream

我写了这个方法:

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());
    }
}

我在这里遇到的问题是我对单词Stream<String>进行了两次操作。为了做到这一点,你必须显式重建这个流,还是有一些我可以使用的魔术重置方法?

另外,为了再次重建单词stream,我必须重建linesStream并将其包装到另一个try / catch块中......非常详细。什么方法可以使这类事情更易于编写?

我想我能做到:

    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();
        }
    }

但这是我剩下的全部吗?

3 个答案:

答案 0 :(得分:3)

您无法重复使用流。只需将元素收集到一个集合中,例如a List,或调用(有状态)函数,该函数输出每个元素并递增计数。

答案 1 :(得分:3)

您不能reset Stream,但可collect distinct()的结果;您还可以使用\\s+作为正则表达式。像,

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

然后更改您的来电者

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);

你不应该硬编码这样的路径,你可以使用user.home系统属性来定位你的文件。像,

return Files.lines(Paths.get(System.getProperty("user.home"), "Desktop/java.txt"));

答案 2 :(得分:2)

问题实际上是流不支持对它们调用多个终端操作,这是一个不幸的限制。

最接近的选择是将处理后的数据收集到一个集合中并运行相同的操作:

List<String> distinctWords = getDistinctWords(lines1)
              .collect(Collectors.toList());

System.out.println("There are " + distinctWords.size() + 
        " distinct words in this file, here they are:");
distinctWords.forEach(System.out::println);

另一种方法是使用有状态行为,在流遍历期间执行的操作会产生副作用:

AtomicLong al = new AtomicLong();
getDistinctWords(lines1).forEach(string -> {
    al.incrementAndGet();
    System.out.println(string);
});

System.out.println("There are " + al.get() + 
        " distinct words in this file, here they are:");

应谨慎使用流中的有状态行为。 documentation of the java.util.stream package有很多关于此的信息。但我相信在这种情况下,副作用不会是不受欢迎的。