代码之家  ›  专栏  ›  技术社区  ›  Coder-Man

你每次都必须重新计算Java流< T >吗?

  •  2
  • Coder-Man  · 技术社区  · 8 年前

    我写了这个方法:

    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> 两次。为了做到这一点,您必须显式地重建这个流,还是有一些我可以使用的魔法重置方法?

    另外,为了重新构建文字流,我必须重新构建 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 回复  |  直到 8 年前
        1
  •  3
  •   jon hanson    8 年前

    你不能重复使用流。只需将元素收集到一个集合中,例如 List 或者调用(有状态)函数,该函数输出每个元素并增加一个计数。

        2
  •  3
  •   Elliott Frisch    8 年前

    你不能 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"));
    
        3
  •  2
  •   ernest_k Petronella    8 年前

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

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

    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 有很多关于这个的信息。但我相信在这种情况下,副作用不会是不受欢迎的。