1. Overview
1.概述
With the introduction of lambda expressions in Java 8, it’s possible to write code in a more concise and functional way. Streams and Functional Interfaces are the heart of this revolutionary change in the Java platform.
随着Java 8中lambda表达式的引入,我们可以用更加简洁和功能化的方式来编写代码。Streams和Functional Interfaces是Java平台中这一革命性变化的核心。
In this quick tutorial, we’ll learn whether we should explicitly close Java 8 streams by looking at them from a resource perspective.
在这个快速教程中,我们将通过从资源角度看,了解我们是否应该显式关闭Java 8流。
2. Closing Streams
2.关闭水流
Java 8 streams implement the AutoCloseable interface:
Java 8 流实现AutoCloseable接口。
public interface Stream<T> extends BaseStream<...> {
// omitted
}
public interface BaseStream<...> extends AutoCloseable {
// omitted
}
Put simply, we should think of streams as resources that we can borrow and return when we’re done with them. As opposed to most resources, we don’t have to always close streams.
简单地说,我们应该将流视为我们可以借用的资源,并在我们用完后归还。与大多数资源相比,我们不必总是关闭流。
This may sound counter-intuitive at first, so let’s see when we should and when we shouldn’t close Java 8 streams.
这听起来可能有违直觉,所以让我们看看什么时候应该和什么时候不应该关闭Java 8流。
2.1. Collections, Arrays, and Generators
2.1.集合、数组和生成器
Most of the time, we create Stream instances from Java collections, arrays, or generator functions. For instance, here, we’re operating on a collection of String via the Stream API:
大多数时候,我们从Java集合、数组或生成器函数中创建Stream实例。例如,在这里,我们通过Stream API对一个String集合进行操作。
List<String> colors = List.of("Red", "Blue", "Green")
.stream()
.filter(c -> c.length() > 4)
.map(String::toUpperCase)
.collect(Collectors.toList());
Sometimes, we’re generating a finite or infinite sequential stream:
有时,我们正在生成一个有限的或无限的顺序流。
Random random = new Random();
random.ints().takeWhile(i -> i < 1000).forEach(System.out::println);
Additionally, we can also use array-based streams:
此外,我们还可以使用基于数组的流。
String[] colors = {"Red", "Blue", "Green"};
Arrays.stream(colors).map(String::toUpperCase).toArray()
When dealing with these sorts of streams, we shouldn’t close them explicitly. The only valuable resource associated with these streams is memory, and Garbage Collection (GC) takes care of that automatically.
在处理这类流时,我们不应该明确地关闭它们。与这些流相关的唯一有价值的资源是内存,而垃圾收集(GC)会自动处理这个问题。
2.2. IO Resources
2.2.IO资源
Some streams, however, are backed by IO resources such as files or sockets. For example, the Files.lines() method streams all lines for the given file:
然而,有些流是由IO资源支持的,如文件或套接字。例如,Files.lines()方法流化了给定文件的所有行。
Files.lines(Paths.get("/path/to/file"))
.flatMap(line -> Arrays.stream(line.split(",")))
// omitted
Under the hood, this method opens a FileChannel instance and then closes it upon stream closure. Therefore, if we forget to close the stream, the underlying channel will remain open and then we would end up with a resource leak.
在引擎盖下,这个方法打开了一个FileChannel实例,然后在流关闭时关闭它。因此,如果我们忘记关闭流,底层通道将继续打开,然后我们将以资源泄漏而告终。
To prevent such resource leaks, it’s highly recommended to use the try-with-resources idiom to close IO-based streams:
为了防止这种资源泄漏,强烈建议使用try-with-resourcesidiom来关闭基于IO的流。
try (Stream<String> lines = Files.lines(Paths.get("/path/to/file"))) {
lines.flatMap(line -> Arrays.stream(line.split(","))) // omitted
}
This way, the compiler will close the channel automatically. The key takeaway here is to close all IO-based streams.
这样,编译器将自动关闭该通道。这里的关键启示是要关闭所有基于IO的流。
Please note that closing an already closed stream would throw IllegalStateException.
请注意,关闭一个已经关闭的流会抛出IllegalStateException。
3. Conclusion
3.总结
In this short tutorial, we saw the differences between simple streams and IO-heavy ones. We also learned how those differences inform our decision on whether or not to close Java 8 streams.
在这个简短的教程中,我们看到了简单流和重度IO流的区别。我们还了解了这些差异是如何让我们决定是否关闭Java 8流的。
As usual, the sample code is available over on GitHub.
像往常一样,样本代码可在GitHub上获得。