在Java 8中,Stream(AutoCloseable)无法重复使用,一旦使用它,流将被关闭。那么使用try-with-resources语句声明的实用程序是什么?
使用try-with-resources语句的示例:
public static void main(String[] args) throws IOException {
try (Stream<Path> entries
= Files.walk(Paths.get("."), 4, FileVisitOption.FOLLOW_LINKS)) {
entries.forEach(x -> System.out.println(x.toAbsolutePath()));// the entries stream will be automatically closed at this point
//..
System.out.println("Still in the Try Block");
} //The entries will be closed again because it is declared in the try-with-resources statement
}
这里没有try catch块的相同示例
public static void main(String[] args) throws IOException {
Stream<Path> entries = Files.walk(Paths.get("."), 4, FileVisitOption.FOLLOW_LINKS);
entries.forEach(x -> System.out.println(x.toAbsolutePath()));// the entries stream will be automatically closed at this point
System.out.println("Is there a risk of resources leak ?");
}
哪一个更安全?
在一些答案之后,我更新了我的代码以检查流是否已经关闭:
这里是新代码:
public static void main(String[] args) throws IOException {
resourceWithTry();
resourceWithoutTry();
}
private static void resourceWithTry() throws IOException {
try (Stream<Path> entries
= Files.walk(Paths.get("."), 4, FileVisitOption.FOLLOW_LINKS).onClose(() -> System.out.println("The Stream is closed"))) {
entries.forEach(x -> System.out.println(x.toAbsolutePath()));// the entries stream will be not automatically closed at this point
System.out.println("Still in the Try Block");
} //The entries will be closed again because it is declared in the try-with-resources statement
}
private static void resourceWithoutTry() throws IOException {
Stream<Path> entries
= Files.walk(Paths.get("."), 4, FileVisitOption.FOLLOW_LINKS).onClose(() -> System.out.println("Without Try: The Stream is closed"));
entries.forEach(x -> System.out.println(x.toAbsolutePath()));// the entries stream will be not automatically closed at this point
System.out.println("Still in the Try Block");
}
答案 0 :(得分:8)
在Java 8中,Stream(AutoCloseable)一旦被重用就无法重用 消耗或使用,流将被关闭。
不完全。
Stream
等forEach()
终端操作不会关闭流
它使流管道不再消耗。
哪个不同。
Package java.util.stream
description州:
执行终端操作后,流管道为 被认为已消耗,不能再使用;如果你需要 再次遍历相同的数据源,您必须返回数据 获取新流的来源。
没有说流已关闭。
因此,在以下代码中,永远不会调用AutoCloseable.close()
实例的Stream
方法:
Stream<Path> entries = Files.walk(Paths.get("."), 4, FileVisitOption.FOLLOW_LINKS);
entries.forEach(x -> System.out.println(x.toAbsolutePath()));
所以总是需要关闭流吗? (使用明确的close()
调用或更好的try-with-resources
)
java.util.stream.Stream<T>
javadocs解释说,使用后几乎所有Stream
个实例都不需要使用AutoCloseable.close()
关闭。
这只适用于IO流。
Streams有一个close()方法并实现AutoCloseable,但差不多 所有流实例实际上不需要在使用后关闭。 通常,只有源是IO通道的流(例如那些 由Files.lines(Path,Charset)返回)将需要关闭。最 流由集合,数组或生成函数支持, 这不需要特殊的资源管理。 (如果有流 要求关闭,可以将其声明为a中的资源 尝试使用资源声明。)
在我们的例子中,你操纵File
,所以关闭频道是有意义的。
通过使用try-with-resources
,可以避免可能发生的资源耗尽异常和错误
如果在处理过程中出现任何错误或异常,则资源可能会全部释放。
答案 1 :(得分:3)
流处理可能会中断,然后它不会被完全消耗,也不会自动关闭。 考虑这个例子:
Stream<Integer> nums = Stream.of(1, 2, 3);
nums.onClose(() -> System.out.println("close was called"));
nums.forEach(x -> { if (x > 1) throw new IllegalStateException(); });
这将在中间崩溃,onClose
将不会被调用。
流保持打开状态,您必须手动关闭它。
如果您使用 try-with-resources ,它将被正确关闭,无论如何, 你可以观察到:
try (Stream<Integer> nums = Stream.of(1, 2, 3)) {
nums.onClose(() -> System.out.println("close was called"));
nums.forEach(x -> { if (x > 1) throw new IllegalStateException(); });
}
这是一个折磨的例子, 因为它不消耗任何需要关闭的资源, 垃圾收集者将清理, 即使溪流没有关闭。
那么使用try-with-resources语句声明的实用程序是什么?
确保流无论如何都会被关闭。 当流不受需要关闭的资源支持时, 它实际上并不重要。
上面的例子只是为了证明这种差异, 但在这样的代码中,使用try-with-resources是不必要的偏执狂, 只是代码中的噪音,所以没有try-with-resources就更好了。
答案 2 :(得分:1)
根据docs,建议(并且更安全)使用try-with-resources关闭此实例中返回的流:
如果需要及时处理文件系统资源,则 应该使用try-with-resources构造来确保 在流操作之后调用stream的close方法 完成。
在其他情况下,Stream
从数组或列表中提供,它没有任何区别。