首页 > 解决方案 > Java 8 flatMapped 流在 try-with-resources 块中关闭

问题描述

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

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

此方法必须在 try-with-resources 语句或类似的控制结构中使用,以确保在流的操作完成后立即关闭流的打开目录。

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

我的问题是为什么我的流被关闭了,尽管我使用mapflatMap返回一个新的流。我是否错误地期望这两种方法返回新Stream实例,因此只有myStream关闭而不是map操作返回的实例?map我对单子有一个模糊的理解,但是flatMap方法的行为意味着Stream不是真正的单子吗?

标签: javajava-8functional-programmingjava-streammonads

解决方案


块完成stream后将关闭。try

因为Stream<T>延伸BaseStream<T, Stream<T>>BaseStream延伸AutoCloseable

为什么我在块中创建的 Stream 实例也关闭了

因为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...");
};

推荐阅读