必须用try-with-resources,因为Files.lines()返回的Stream持有文件句柄,不显式关闭易致“Too many open files”;for-each或forEach等不会自动关闭,仅终端操作执行完也不关,须靠try-with-resources或手动close。

直接用 Files.lines() 配合 try-with-resources 是最简洁、安全的方式,因为返回的 Stream 实现了 AutoCloseable,JVM 会在 try 块结束时自动关闭底层文件句柄。
为什么必须用 try-with-resources?
Files.lines() 返回的是一个延迟绑定、基于 NIO 的流,它内部持有一个 FileChannel 或类似资源。如果不显式关闭,流被 GC 回收前句柄可能一直占用——尤其在处理大文件时,容易触发“Too many open files”异常。
注意:普通 for-each 遍历或 stream.forEach() 不会自动关闭流;只有终端操作(如 count()、collect())完成后也不关;必须靠 try-with-resources 或手动调用 close()。
标准写法(推荐)
把 Files.lines() 放在 try 括号里,流对象在作用域结束时自动关闭:
try (Stream<string> lines = Files.lines(Paths.get("huge.log"), StandardCharsets.UTF_8)) {
long count = lines.filter(line -> line.contains("ERROR")).count();
System.out.println("Error lines: " + count);
} catch (IOException e) {
// 处理 IO 异常(比如文件不存在、权限不足)
e.printStackTrace();
}</string>
这样写,无论正常执行完还是中途抛异常,流都会被关闭。
常见错误与规避方式
-
不要提前终止流却不关闭:比如用
findFirst()后就丢弃流——虽然操作完成,但流未关闭。应仍放在 try-with-resources 中。 -
避免多次遍历同一 stream:Stream 只能消费一次。若需多次使用,要么重新获取 stream,要么先
collect(Collectors.toList())转成集合(注意内存开销)。 - 别混用 parallelStream 和 try-with-resources:并行流本身不改变 close 行为,但若在流中启动异步任务并持有 stream 引用,可能造成关闭时机不可控——保持逻辑线性、在 try 块内完成所有操作最稳妥。
需要额外控制时:手动 close(少用)
极少数场景(如流生命周期跨方法边界),可显式管理:
Stream<string> lines = null;
try {
lines = Files.lines(Paths.get("data.csv"));
lines.map(String::trim).filter(s -> !s.isEmpty()).forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (lines != null) lines.close(); // 必须判空再关
}</string>
但 try-with-resources 更可靠、代码更短,应作为默认选择。










