1. 概述
随着Java 8中lambda表达式的引入,可以以更简洁和更实用的方式编写代码。Stream和函数接口是Java平台这一革命性变化的核心。
在这个快速教程中,我们将了解是否应该通过从资源角度查看Java Stream来显式关闭它们。
2. 关闭流
Java Stream实现了AutoCloseable接口:
public interface Stream<T> extends BaseStream<...> {
// omitted
}
public interface BaseStream<...> extends AutoCloseable {
// omitted
}
简而言之,我们应该将流视为可以借用并在用完后归还的资源。与大多数资源相反,我们不必总是关闭流。
起初这听起来可能违反直觉,所以让我们看看何时应该以及何时不应该关闭Java Stream。
2.1 集合、数组和生成器
大多数时候,我们从Java集合、数组或生成器函数创建Stream实例。例如,在这里,我们通过Stream API对字符串集合进行操作:
List<String> 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)会自动处理。
2.2 IO资源
但是,某些流由IO资源(如文件或套接字)支持。例如,Files.lines()方法流式传输给定文件的所有行:
Files.lines(Paths.get("/path/to/file"))
.flatMap(line -> Arrays.stream(line.split(",")))
// omitted
在幕后,此方法打开一个FileChannel 实例,然后在流关闭时将其关闭。因此,如果我们忘记关闭流,底层通道将保持打开状态,然后我们将以资源泄漏告终。
为防止此类资源泄漏,强烈建议使用try-with-resources习惯用法来关闭基于IO的流:
try (Stream<String> lines = Files.lines(Paths.get("/path/to/file"))) {
lines.flatMap(line -> Arrays.stream(line.split(","))) // omitted
}
这样,编译器会自动关闭通道。这里的关键要点是关闭所有基于IO的流。
请注意,关闭一个已经关闭的流会抛出IllegalStateException。
3. 总结
在这个简短的教程中,我们看到了简单流和IO密集流之间的区别。我们还了解了这些差异如何影响我们决定是否关闭Java Stream。
与往常一样,本教程的完整源代码可在GitHub上获得。
Show Disqus Comments
Post Directory
扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章