关闭映射流 - 这是什么想法?

时间:2016-01-16 21:49:07

标签: java java-8 java-stream

众所周知,Javadoc说Stream接口:

  

Streams有一个BaseStream.close()方法并实现AutoCloseable,   但几乎所有流实例实际上都不需要关闭   使用后。 通常,只有源为IO通道的流(例如   由Files.lines(Path,Charset)返回的那些将需要关闭。   大多数流都由集合,数组或生成支持   功能,不需要特殊的资源管理。 (如果是一个流   确实需要关闭,它可以被声明为一个资源   尝试使用资源声明。)

好的,但同时在此界面中有flatMapToInt等方法:

IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);

Javadoc规范说:

  

每个映射的流在放入其内容后关闭   这个流。

所以,我没有想到:如果IntStream没有设计为在其源代码中有IO通道,为什么它在此方法中关闭?

例如,ReferencePipeline实现以这种方式执行:

try (IntStream result = mapper.apply(u)) {     
   if (result != null)
       result.sequential().forEach(downstreamAsInt);
}

更一般的问题可能是:我们是否应关注像IntStream(或其后代)那样关闭流?如果没有,那么为什么flatMapTo*关心?

编辑 @Tunaki提供了非常有趣的email link。但这一切都是flatMap,我同意在一般情况下我们应该关闭。但我的问题是关于特殊情况:flatMapToIntflatMapToLong等等,我认为没有必要关闭流。

EDIT-2 @BrianGoetz在这里上诉,因为这是他引用的电子邮件,因此他在主题中:)

1 个答案:

答案 0 :(得分:15)

关于资源处理的一般规则是whoever is responsible for closing a resource is the one that opened itflatMap操作是Stream API中唯一一个打开Stream的操作,因此它是唯一可以关闭它的操作。

引自this mail的Brian Goetz说:

  

总而言之,flatMap()是内部关闭的唯一操作   流完成后,有充分的理由 - 这是唯一的情况   由操作本身有效地打开流,因此   也应该通过操作关闭。假设任何其他流   由来电者打开,因此应由来电者关闭。

给出的例子如下。考虑

try (Stream<Path> paths = Files.walk(dir)) {
    Stream<String> stream = paths.flatMap(p ->  {
        try {
            return Files.lines(p);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    });
}

方法参考Files::lines返回文件行的Stream<String>行。当平面映射操作结束时,预期用于读取文件的打开资源被关闭。问题是:关闭什么?好吧,由flatMap本身关闭,因为它是首先打开Stream的操作。

Files.lines返回一个Stream,其中包含一个预先注册的关闭处理程序,用于关闭基础BufferedReader。完成flatMap操作后,将调用此关闭处理程序并正确释放资源。

这个想法被移植到flatMapTo*操作的原因是相同的:坚持上述规则,即流程分配的每个资源都应该由该流程关闭。

为了表明您可以构建一个可以关闭基础资源的IntStream,请考虑以下Stream管道,其中每个路径都不是平面映射到其行,而是每行中的字符数。< / p>

try (Stream<Path> paths = Files.walk(dir)) {
    IntStream stream = paths.flatMapToInt(p ->  {
        try {
            return Files.lines(p).mapToInt(String::length);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    });
}