Stream的javadoc说明:
Streams有一个BaseStream.close()方法并实现AutoCloseable,但几乎所有的流实例实际上都不需要在使用后关闭.通常,只有源为IO通道的流(例如Files.lines(Path,Charset)返回的流)才需要关闭.大多数流都由集合,数组或生成函数支持,不需要特殊的资源管理.(如果流确实需要关闭,则可以在try-with-resources语句中将其声明为资源.)
因此,绝大多数情况下,人们可以在单行中使用Streams,collection.stream().forEach(System.out::println);
但是对于Files.lines
和其他资源支持的流,必须使用try-with-resources语句或泄漏资源.
这让我觉得容易出错并且不必要.因为Streams只能迭代一次,所以在我看来,没有一个迭代后Files.lines
不应该关闭输出的情况,因此实现应该只是在任何终端操作结束时隐式调用close .我错了吗?
是的,这是一个深思熟虑的决定.我们考虑了两种选择.
这里的操作设计原则是"获取资源的人应该释放资源".阅读EOF时文件不会自动关闭; 我们希望打开文件的人明确关闭文件.由IO资源支持的流是相同的.
幸运的是,该语言为您提供了一种自动化的机制:try-with-resources.由于Stream实现AutoCloseable,您可以执行以下操作:
try (Streams = Files.lines(...)) { s.forEach(...); }
"自动关闭真的很方便,所以我可以把它写成一个单行"的说法很好,但主要是尾巴摇尾巴.如果您打开了文件或其他资源,则还应该准备关闭它.有效和一致的资源管理胜过"我想在一行中写出来",我们选择不扭曲设计只是为了保持一线性.
除了@BrianGoetz之外,我还有更具体的例子.不要忘记Stream
有逃生舱的方法iterator()
.假设你这样做:
Iteratoriterator = Files.lines(path).iterator();
之后,你可以调用hasNext()
和next()
几次,然后就放弃这个迭代器Iterator
接口完美支持这样使用.没有办法明确关闭Iterator
,你可以在这里关闭的唯一对象是Stream
.所以这样它可以很好地工作:
try(Streamstream = Files.lines(path)) { Iterator iterator = stream.iterator(); // use iterator in any way you want and abandon it at any moment } // file is correctly closed here.