Java中第二次调用Supplier的get方法获取流时计数为0的问题
StreamSupplier二次调用返回0的原因与解决办法
问题现象
- 首次调用
streamSupplier.get()可正常打印app_log.log文件的所有行,但第二次调用count()返回0 - 若将
count()作为首次调用,能得到正确计数528,但后续无法打印文件内容
原代码:
import java.io.BufferedReader; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.function.Supplier; import java.util.stream.Stream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FileOperations { private Logger logger = LoggerFactory.getLogger(getClass()); public static void main(String[] args) { FileOperations fOps = new FileOperations(); fOps.usingBufferedReader(); } public void usingBufferedReader() { Path path = Path.of("app_log.log"); try (BufferedReader reader = Files.newBufferedReader(path);) { Supplier<Stream<String>> streamSupplier = () -> reader.lines(); streamSupplier.get().forEach(ln -> { System.out.println(ln); }); long count = streamSupplier.get().count(); System.out.println("count = " + count); } catch (IOException e) { logger.error("IOException: %s%n", e); } } }
核心原因
BufferedReader.lines()返回的Stream是单次消费型的,一旦执行终端操作(如forEach、count),Stream就会被耗尽并关闭,同时底层BufferedReader的读取指针已经移动到文件末尾- 你的
Supplier复用了同一个BufferedReader生成Stream,第一次操作已经读完了所有文件内容,第二次生成的Stream自然没有数据,所以返回0
解决方案
方案1:每次生成新的BufferedReader
将创建BufferedReader的逻辑放入Supplier,每次调用get()都会重新打开文件流:
public void usingBufferedReader() { Path path = Path.of("app_log.log"); Supplier<Stream<String>> streamSupplier = () -> { try { return Files.newBufferedReader(path).lines(); } catch (IOException e) { throw new UncheckedIOException(e); } }; streamSupplier.get().forEach(System.out::println); long count = streamSupplier.get().count(); System.out.println("count = " + count); }
注意:此方法会多次读写文件,适合小文件场景;大文件频繁IO会有性能损耗。
方案2:缓存文件内容到集合
若文件体积不大,先一次性读取所有内容到内存集合,后续操作复用集合的Stream:
import java.util.List; public void usingBufferedReader() { Path path = Path.of("app_log.log"); try { List<String> lines = Files.readAllLines(path); lines.forEach(System.out::println); long count = lines.stream().count(); System.out.println("count = " + count); } catch (IOException e) { logger.error("IOException: %s%n", e); } }
优势:仅读取一次文件,后续操作都是内存操作,性能更优;缺点是会占用内存存储整个文件内容。
内容的提问来源于stack exchange,提问作者learner
相关产品推荐
相关产品推荐

