我需要关闭由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()));我该怎么做?
谢谢。
发布于 2020-12-23 14:38:22
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()
P.S.:阅读rzwitserloot的答案,它包含有用的信息。
发布于 2020-12-23 14:38:03
根据Javadoc
需要对文件系统资源进行..If的及时处理,应该使用“使用资源进行尝试”结构来确保流操作完成后调用流的关闭方法。
try (Stream<String> stream = Files.lines(fileP, Charset.forName("UTF-8"))) {
stream.map(line -> line.replaceAll("[.?!]$"," % "))
...//rest of code here
}发布于 2020-12-23 14:38:53
流的API不是以这种方式使用的。不幸的是,溪流/功能/可选等是当前的‘味道’,有大量的狂热者和改信者,他们已经找到了他们的宗教,现在正在积极地试图改变他们所能找到的每一个灵魂。正如您所写的,这些代码在他们看来是“干净的”(在旁观者眼中是一个术语,但我可以看到这种代码风格对许多人来说是多么的好),这已经扩展到那些经常犯错误的甲骨文教程中。然而,javadoc明确说明了您应该如何使用流。这不是怎么回事。
来自Files.lines的javadoc
返回的流封装一个Reader。如果需要及时处理文件系统资源,则应使用“使用资源进行尝试”结构来确保流操作完成后调用流的关闭方法。
这是一句轻描淡写的话;“如果需要及时处理文件系统资源”,这是一种有趣的说法:“如果您希望您的VM不成为边缘无用的,因为它耗尽了文件句柄,并且由于无法打开jar文件在某些类中读取而面临崩溃的风险”。
因此,您必须按它说的做:将它们封装在“使用资源”的尝试块中。任何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操作最终抛出,您的流将保持未关闭状态。
https://stackoverflow.com/questions/65425961
复制相似问题