Java 8 flatMapped 流在 try-with-resources 块中关闭

Java 8 flatMapped stream closed in try-with-resources block

我有两种方法 return 列表中字符串的长度,如下所示;

    private Stream<Integer> method1(List<String> list) {
        try (final Stream<String> myStream = list.stream()) {
            return myStream.map(String::length);
        }
    }

    private Stream<Integer> method2(List<String> list) {
        try (final Stream<String> myStream = list.stream()) {
            return myStream.map(String::length).flatMap(Stream::of);
        }
    }

当我尝试使用其中一种方法的结果流时;

    List<Integer> collect = method1(list).collect(Collectors.toList());

    List<Integer> collect = method2(list).collect(Collectors.toList());

我明白了

    Exception in thread "main" java.lang.IllegalStateException: source already consumed or closed

现在我知道在 try-with-resources 块中使用流并不常见。但在我的真实代码中,我在 try-with-resources 中使用 Stream<Path> paths = Files.walk(Path.of(myPath))。在 Files.walk(..) 方法的文档中它说

This method must be used within a try-with-resources statement or similar control structure to ensure that the stream's open directories are closed promptly after the stream's operations have completed.

上面的代码只是一个例子来说明问题。

我的问题是,尽管我使用 mapflatMap 到 return 新流,但为什么我的流被关闭了。我是否错误地期望这两种方法 return new Stream 实例因此只有 myStream 被关闭而不是来自 map 操作的 returned ?我对 monad 的理解很模糊,但是 mapflatMap 方法的行为是否意味着 Stream 不是真正的 monad?

一旦 try 块完成,stream 将关闭。

因为 Stream<T> 扩展了 BaseStream<T, Stream<T>>BaseStream 扩展了 AutoCloseable

why the Stream instance I created in the block is also closed

因为在块中创建的新Stream实例是链式嵌套 myStream 的流,将在 myStream (外部流)关闭后立即关闭。您可以使用 onClose 验证它,如下所示,

privat Stream<Integer> method1(List<String> list) {
    try (final Stream<String> myStream = list.stream()) {
        Stream<Integer> integerStream = myStream.onClose(r)
                .map(String::length).onClose(r1);
        return integerStream;
    }
}
Runnable r = ()->{
    System.out.println("closed main stream...");
};
Runnable r1 = ()->{
    System.out.println("closed map stream...");
};