You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 08:27:23