list.stream().filter(....).collect(..).....
,那么这个流什么时候关闭?我们是否应该像下面的例子那样手动关闭这个流是一种好的做法吗?
Stream<String> stream = list.stream();
String result = stream.limit(10).collect(Collectors.joining(""));
stream.close();
list.stream().filter(....).collect(..).....
,那么这个流什么时候关闭?Stream<String> stream = list.stream();
String result = stream.limit(10).collect(Collectors.joining(""));
stream.close();
一般来说,不需要关闭所有流。你只需要关闭使用IO资源的流。
根据流文件文档:
流有
BaseStream.close()
方法并实现AutoCloseable
接口,但几乎所有的流实例在使用后都不需要被关闭。通常,只有源是IO通道(如Files.lines(Path, Charset)
返回的那些)的流需要被关闭。大多数流都由集合、数组或生成函数支持,这些都不需要特殊的资源管理。(如果一个流确实需要关闭,它可以在try-with-resources语句中声明为资源。)
如果需要关闭流,则最佳做法是使用try-with-resources语句:
try ( Stream<String> stream = Files.lines(path, charset) ) {
// do something
}
默认情况下,您应该关闭流。
流是一个非常通用的API;它代表了一系列数据,而不需要数据的使用者理解数据来自何处。
关闭不需要关闭的流不会产生任何成本;而未能关闭需要关闭的流可能会导致严重问题。您有多么确定您正在编写的代码,目前消耗的数据流不需要关闭,将来永远不会被重新用于消耗需要关闭的不同类型的数据流?
我刚刚完成了大量代码的重构,以前使用内存数据库,现在改为使用SQL后端。涉及的代码经常使用流,这是有充分理由的。将JDBC结果集封装在流中意味着我可以轻松地实现我的目标。但是...我的新流封装了一个需要关闭的资源,而旧流则没有。因为原始开发人员(在这种情况下是我,我很自责)没有关闭流,所以需要进行许多繁琐的调试。
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
// "--" is not printed at all:
list.stream().onClose(()->System.out.println("--")).forEach(x -> System.out.println(x));
System.out.println("with try(){}:");
// "--" is printed:
try (Stream<Integer> stream = list.stream() ) {
stream.onClose(() -> System.out.println("--")).forEach(x -> System.out.println(x));
}
正如我不断强调的那样,这取决于您的用例。 我使用的推论是:用例的上下文决定了代码。
因此,文件(如已经说明的那样),扫描器和套接字需要手动关闭。 规则是关闭所有基于IO的流。
那么集合,数组和生成器呢? 引用Baeldung文章中的话:我们应该关闭Java Stream吗?
大多数情况下,我们从Java集合、数组或生成器函数创建Stream实例。例如,在这里,我们通过Stream API操作String集合:List colors = List.of("Red", "Blue", "Green") .stream()
.filter(c -> c.length() > 4) .map(String::toUpperCase)
.collect(Collectors.toList());
Random random = new Random(); random.ints().takeWhile(i -> i < 1000).forEach(System.out::println);
此外,我们还可以使用基于数组的流:String[] colors = {"Red", "Blue", "Green"}; Arrays.stream(colors).map(String::toUpperCase).toArray()
在处理这些类型的流时,我们不应该显式地关闭它们。与这些流相关的唯一有价值的资源是内存,垃圾回收(GC)会自动处理它。我之前不知道的另一个用例是:
返回一个流,其中包含将此流的每个元素替换为应用提供的映射函数到每个元素上产生的映射流的内容的结果。每个映射流在其内容被放入此流后都会被关闭。(如果映射流为空,则使用空流。)
感谢Mike在使用Autoclosable关闭Java流中指出了这一点。
因此,使用情况确定何时以及如何关闭流。
你需要关闭的流之一是来自org.hibernate.query.Query#getResultStream
的流。
你可以使用try-with-resources来实现:
try (Stream<SomeEntity> resultStream = query.getResultStream()) {
// process the stream
}
DirectoryStream
,需要关闭。最好的方法是使用“try-with-resources”语句。具体使用方法请见官方文档。 - JesperAutoCloseable
接口,因此当流处于空闲状态时,打开的流会被关闭。