考虑以下代码:
Path directory = Paths.get(/* some directory */);
Files.list(directory).forEach(System.out::println);
终端操作(如
forEach
)是否会关闭已打开的底层文件?
参考Files.list的javadoc相关部分:
返回的流封装了一个DirectoryStream。如果需要及时处理文件系统资源,则应使用 try-with-resources 构造来确保在流操作完成后调用流的 close 方法。
如果它不调用
Stream.close()
,那么在生成可维护代码时调用它的最佳替代方案是什么?
终端操作员不会自动关闭流。考虑这段代码:
Stream<Path> list = Files.list(directory).onClose(() -> System.out.println("Closed"));
list.forEach(System.out::println);
这不会打印“已关闭”。
但是,以下内容确实打印“已关闭”:
try (Stream<Path> list = Files.list(directory).onClose(() -> System.out.println("Closed"))) {
list.forEach(System.out::println);
}
所以最好的方法是使用 try-with-resources 机制。
在 Java 9+ 中,可以在
try
之前声明和实例化资源。请参阅JEP 213。
Stream<Path> list = Files.list(directory).onClose(() -> System.out.println("Closed")) ;
…
try (list) {
list.forEach(System.out::println);
}
因此快速检查发现
forEach
并未关闭 DirectoryStream
:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.function.Consumer;
import java.util.stream.Stream;
/**
* Created for http://stackoverflow.com/q/27381329/1266906
*/
public class FileList {
public static void main(String[] args) {
Path directory = Paths.get("C:\\");
try {
Stream<Path> list = Files.list(directory).onClose(() -> System.out.println("Close called"));
list.forEach(System.out::println);
// Next Line throws "java.lang.IllegalStateException: stream has already been operated upon or closed" even though "Close called" was not printed
list.forEach(System.out::println);
} catch (IOException | IllegalStateException e) {
e.printStackTrace(); // TODO: implement catch
}
// The mentioned try-with-resources construct
try (Stream<Path> list = Files.list(directory)) {
list.forEach(System.out::println);
} catch (IOException | IllegalStateException e) {
e.printStackTrace(); // TODO: implement catch
}
// Own helper-method
try {
forEachThenClose(Files.list(directory), System.out::println);
} catch (IOException | IllegalStateException e) {
e.printStackTrace(); // TODO: implement catch
}
}
public static <T> void forEachThenClose(Stream<T> list, Consumer<T> action) {
try {
list.forEach(action);
} finally {
list.close();
}
}
}
我看到了两个提出的缓解措施:
Files.list
JavaDoc哪个更易于维护可能取决于您需要多少个辅助方法。