我需要关闭这个由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
操作最终抛出,您的流将保持未关闭状态。