Files.lines : close stream



我需要关闭这个由Files.lines:创建的流

Map<String, Long> wordCounts =
Files.lines(fileP, Charset.forName("UTF-8"))
.map(line -> line.replaceAll("[.?!]$"," % "))
.flatMap(line -> pattern.splitAsStream(line))
.collect(Collectors.groupingBy(String::toLowerCase,
TreeMap::new, Collectors.counting()));

我该怎么办
谢谢。

根据Javadoc

[..]如果需要及时处理文件系统资源,则应使用try-with-resources构造来确保在流操作完成后调用流的关闭方法。

try (Stream<String> stream = Files.lines(fileP, Charset.forName("UTF-8"))) {
stream.map(line -> line.replaceAll("[.?!]$"," % "))
...//rest of code here
}

Files.lines实现了AutoCloseable,因此可以将try-catch与资源一起使用。

try(Stream<String> fileLines = Files.lines(fileP, Charset.forName("UTF-8"))){
Map<String, Long> wordCounts = fileLines.map(line -> line.replaceAll("[.?!]$"," % "))
.flatMap(line -> pattern.splitAsStream(line))
.collect(Collectors.groupingBy(String::toLowerCase,
TreeMap::new, Collectors.counting()));
}catch(Exception e){
e.printStackTrace();
}

try块执行后,自动调用fileLines.close()

第页。S.:阅读rzwitserloot的答案,其中包含有用的信息。

流的API不打算以这种方式使用。不幸的是,流媒体/功能/可选等是当前的"潮流",有很多狂热者和改宗者已经找到了自己的宗教,现在正积极尝试改变他们能找到的每一个灵魂。正如你所写的,代码在他们看来是"干净的"(这是旁观者眼中的一个术语,但我可以看到这种风格的代码对许多人来说是多么的好(,这已经扩展到了那些总是犯错的预言家教程本身。然而,javadoc明确说明了应该如何使用流。但事实并非如此。

来自Files.lines:的javadoc

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

这是一句轻率的话;'如果需要及时处理文件系统资源"是一种有趣的说法,"如果你希望你的虚拟机不会因为文件句柄用完而变得近乎无用,并且由于甚至无法打开jar文件在某些类中读取而面临崩溃的风险"。

因此,您必须按照它所说的去做:将它们封装在try-with-resources块中。任何Stream都可以这样包装(因为Stream实现了AutoClosable-它有一个close()方法(:

Map<String, Long> wordCounts;
try (var stream = Files.lines(fileP)) {
wordCounts = stream
.map(...)
.flatMap(...)
.collect(...);
}

注意:这里不需要指定UTF-8;与java核心运行时中的大多数基本方法不同,如果未指定编码,则所有隐式将字节转换为字符或将字节转换成字符的Files方法都将使用UTF-8。

NB2:流上的终端操作,如.collect,在完成后确实会关闭底层流。问题是:如果您的某个.map操作最终抛出,您的流将保持未关闭状态。

最新更新