自动关闭资源的 Java 8 Stream(基于资源).iterator()?

web*_*ter 5 java iterator java-8 java-stream

Java 8 完成后会Stream.iterator()自动关闭流吗?我想不是...

我有这样的事情:

class Provider implements Serializable {

  Iterator<String> iterator() {
    Stream<String> stream = new BufferedReader(...).lines();
    return stream.iterator();
  }
}
Run Code Online (Sandbox Code Playgroud)

这个迭代器被其他一些不知道迭代器基于文件读取资源的类使用。那是

class Consumer {
  void f() {
    Iterator<String> iterator = provider.iterator();
    // code that calls iterator methods at non-determined times
  }
}
Run Code Online (Sandbox Code Playgroud)

我必须流式传输文件,因为它太大而无法放入内存。但是我希望能够在迭代器没有更多元素时自动关闭资源,这样我就不会泄漏资源。该Provider班是Serializable,我不能有任何的流或BufferedReader中的成员。

有没有好的方法可以做到这一点?

Tag*_*eev 2

首先,请注意,您创建的流BufferedReader.lines不包含任何资源,因此关闭流没有任何效果:

BufferedReader br = new BufferedReader(...);
try(Stream<String> stream = br.lines()) {
   ... use stream
}
// br is still open here!
Run Code Online (Sandbox Code Playgroud)

通常,如果流持有资源,则会明确记录。例如,Files.lines记录以下内容:

返回的流封装了一个Reader. 如果需要及时处理文件系统资源,则应使用 try-with-resources 构造来确保在close流操作完成后调用流的方法。

文档中没有这样的注释BufferedReader.lines

BufferedReader因此,在您的情况下,如果它确实拥有需要关闭的资源,则您有责任关闭它。情况并非总是如此。例如,如果您 create new BufferedReader(new StringReader(string)),则没有任何要关闭的资源,因此根本不调用该close()方法也可以。

无论如何,回到你的问题。假设流实际上持有一个资源(例如,从 中创建Files.lines()),如果您只是返回一个迭代器,则无论该迭代器是否遍历到末尾,它都不会自动关闭。close()如果您想在某个特定时刻关闭流,则必须显式调用流上的方法。否则,您必须依赖垃圾收集器,它最终会将底层资源对象(例如FileInputStream)放入终结队列中,最终将调用finalize该对象的方法来关闭文件。您无法保证这种情况何时发生。

另一种方法是将整个输入文件缓冲到内存中(假设它不是很长)并在返回迭代器之前关闭文件。您可以在没有任何流 API 的情况下执行此操作来读取文件:

return Files.readAllLines(pathToTheFile).iterator();
Run Code Online (Sandbox Code Playgroud)