【问题标题】:Java 8: Supplier working with files throws "stream has already been operated upon or closed"Java 8:处理文件的供应商抛出“流已被操作或关闭”
【发布时间】:2017-06-13 02:24:20
【问题描述】:

使用JUnitStream 我收到以下错误消息:

java.lang.IllegalStateException: stream has already been operated upon or closed

我做了一项研究,很明显不可能重用流

但是根据这篇文章:

使用Supplier 可以解决此问题。

所以我当前的代码如下:

    try (Stream<String> stream =  Files.lines(Paths.get(fileName)) ) {

        Supplier<Stream<String>> supplier = () -> stream;

        logger.info("A");
        logger.info("ABC {}", supplier.get().findFirst().get());
        logger.info("B");
        logger.info("XYZ {}", supplier.get().skip(1050).findFirst().get());
        logger.info("C");

        assertThat(supplier.get().count(), is(1051));

    }
    catch (IOException e) {
        logger.error("{}", e.getMessage());
    }

您如何看到我使用supplier.get()Stream 一起工作(它根据教程),但@Test 打印直到B ,因此@Testsupplier.get().skip(1050).findFirst().get() 中失败,它仍然生成相同的错误消息。

我的代码和教程之间的独特区别是,mime 通过文件工作,而教程围绕数组工作。

有什么特别的东西可以毫无问题地编辑吗?

阿尔法

我做了以下版本(按照尤金的sn-p代码)

   try (Stream<String> stream =  Files.lines(Paths.get(fileName)) ) {

        Supplier<Stream<String>> supplier = () -> stream.collect(Collectors.toList()).stream();

        logger.info("A");
        logger.info("ABC {}", supplier.get().findFirst().get());
        logger.info("B");
        logger.info("XYZ {}", supplier.get().skip(1050).findFirst().get());
        logger.info("C");

        assertThat(supplier.get().count(), is(1051));

    }

同样的错误信息。

【问题讨论】:

    标签: java java-8 java-stream


    【解决方案1】:

    Supplier 并不神奇,您仍然需要始终从该供应商处提供一个新流

    所以你可以这样做:

    Supplier<Stream<String>> supplier = () -> Files.lines(Paths.get(fileName));
    

    但这意味着要一直读取文件。您可以将所有行读入单个List,将其存储在内存中,然后将stream 存储在其中。

    List<String> allLines = Files.readAllLines(Paths.get(fileName));
    
    Supplier<Stream<String>> supplier = () -> allLines.stream();
    

    请注意,即使您链接的教程也会返回一个新的流,它是通过Stream.of 创建的,如下所示:

     Supplier<Stream<String>> streamSupplier = () -> Stream.of(array);
    

    【讨论】:

    • 你可以使用Files.readAllLines(...)直接返回一个列表。
    • 谢谢,看来我做错了什么。请参阅我原帖中的Alpha 部分
    • @ManuelJordan 你一直在使用和消费相同的stream
    • @ManuelJordan 当您多次重复使用 lambda 时,您无法在 lambda 中重复使用流。
    • 但是它与日志框架的整个概念相矛盾,无条件读取文件,只是为了提供可能是无操作的日志语句,具体取决于配置的日志级别......
    【解决方案2】:

    这是因为您的供应商始终提供相同的Stream 实例,而您已经使用findFirst() 使用它。然后你尝试用findFirst()再次消费它,这是不允许的。

    在本教程中,每次都会创建一个新流。在您的情况下,您必须在供应商内部调用 Files.lines() 才能使其工作,尽管这意味着您每次都重新读取文件。

    【讨论】:

    • 谢谢,如果你能分享一些sn-p代码会更有价值,谢谢。
    • @Eugene 已经做到了,只需使用 readAllLines() 从文件中获取行列表,然后每次在供应商中使用他提供的代码从中创建流。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-13
    相关资源
    最近更新 更多