bufferedreader.lines() 返回懒加载 stream,需用 try-with-resources 确保 bufferedreader 关闭;避免 collect 全量加载,优先链式调用 filter/map 后接 foreach/findfirst 等终端操作;注意编码显式指定,takewhile 适合短路读取;但无法获行号、不可重用,复杂结构解析仍宜用传统循环。

BufferedReader.lines() 返回一个懒加载的 Stream
用 try-with-resources 自动管理资源
lines() 返回的 Stream 底层持有 BufferedReader,但Stream 本身不自动关闭底层 Reader。必须显式确保 BufferedReader 关闭,否则可能泄露文件句柄。
正确写法:将 BufferedReader 声明在 try 括号内,配合 lines() 使用:
try (BufferedReader reader = Files.newBufferedReader(Paths.get("data.txt"))) {
reader.lines()
.filter(line -> !line.trim().isEmpty())
.map(String::toUpperCase)
.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
这样即使流中途抛异常或提前终止(如 findFirst()),reader 仍会被自动关闭。
避免 collect() 全量加载,优先使用终端操作
lines() 是惰性求值的,但一旦调用 collect(Collectors.toList()) 或 toArray(),就会把全部行读入内存——对大文件很危险。
高效做法是直接链式调用无状态中间操作(filter/map),再用适合场景的终端操作:
- forEach / forEachOrdered:适合逐行消费(如写日志、入库)
- findFirst / findAny:快速查找首行匹配项,读到即停
- count / anyMatch / allMatch:统计或校验,不保留内容
- reduce:做聚合(如累计行数、拼接字符串),注意控制中间结果大小
处理编码与异常更稳妥的方式
Files.newBufferedReader() 默认使用 UTF-8,但若文件编码不确定,应显式指定:
Charset charset = StandardCharsets.GBK; // 或从配置读取
try (BufferedReader reader = Files.newBufferedReader(Paths.get("log.txt"), charset)) {
reader.lines()
.takeWhile(line -> !line.contains("END")) // Java 9+
.map(line -> line.replaceAll("\s+", " "))
.skip(1) // 跳过标题行
.limit(1000) // 只处理前 1000 行
.forEach(processLine());
}
注意:takeWhile(Java 9+)比 filter 更适合“遇到某条件就停止读取”的场景,它会在首个不满足条件时短路,不再读后续行。
替代方案对比:什么时候不该用 lines()
lines() 简洁高效,但有局限:
- 无法获取当前行号(需手动计数)
- 不能回退或重复遍历(Stream 只能消费一次)
- 若需同时读多行(如解析块结构),lines() + reduce 容易变复杂,此时更适合传统 while (reader.readLine() != null)
例如解析 ini 风格配置([section] 开头的分段),用传统循环 + 状态机更清晰可靠。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











