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

使用Java Stream按文件大小总和阈值分组自定义FileInfo对象列表

问题描述

现有自定义类FileInfo:

public class FileInfo {
    private String filePath;
    private Long fileSize;
    private String status;

    // 需提供getFileSize()等getter方法
}

以及List<FileInfo>类型的文件列表,需要将其拆分为多个子列表,每个子列表中所有元素的fileSize总和不超过指定阈值,最终返回List<List<FileInfo>>类型结果。已通过普通for-each循环实现,现需改用Java Stream/Collectors完成。

解决方案思路与实现

Java Stream原生没有直接支持这种基于累加阈值的拆分操作,因为Stream的多数操作是无状态的,而该需求需要维护累加状态(当前子列表的大小总和)。我们可以通过自定义Collector实现,核心逻辑如下:

  1. 定义一个状态容器类,跟踪当前子列表的元素、累计大小,以及最终的拆分结果;
  2. 实现Collector的核心方法:提供容器、累加元素(判断是否需要新建子列表)、合并多线程容器(适配并行流)、转换为最终结果。

具体代码实现

1. 定义状态容器类

class BatchHolder {
    private final long threshold;
    private List<FileInfo> currentBatch = new ArrayList<>();
    private long currentSize = 0L;
    private List<List<FileInfo>> result = new ArrayList<>();

    public BatchHolder(long threshold) {
        this.threshold = threshold;
    }

    // 向当前批次添加元素,超过阈值则归档当前批次并新建
    public void add(FileInfo file) {
        long fileSize = file.getFileSize();
        if (currentSize + fileSize > threshold && !currentBatch.isEmpty()) {
            result.add(currentBatch);
            currentBatch = new ArrayList<>();
            currentSize = 0L;
        }
        currentBatch.add(file);
        currentSize += fileSize;
    }

    // 处理最后一个未归档的批次
    public List<List<FileInfo>> finish() {
        if (!currentBatch.isEmpty()) {
            result.add(currentBatch);
        }
        return result;
    }

    // 合并两个BatchHolder,适配并行流场景
    public BatchHolder merge(BatchHolder other) {
        this.result.addAll(other.result);
        // 将另一个容器的当前批次元素逐个加入,保证阈值规则
        other.currentBatch.forEach(this::add);
        return this;
    }
}

2. 实现自定义Collector

public static Collector<FileInfo, BatchHolder, List<List<FileInfo>>> batchBySize(long threshold) {
    return Collector.of(
        // 提供状态容器实例
        () -> new BatchHolder(threshold),
        // 累加元素到容器
        BatchHolder::add,
        // 合并多线程的容器结果
        BatchHolder::merge,
        // 转换为最终的拆分列表
        BatchHolder::finish
    );
}

3. 使用示例

List<FileInfo> fileList = ...; // 你的原始文件列表
long sizeThreshold = 1024 * 1024; // 示例阈值:1MB
List<List<FileInfo>> batchedList = fileList.stream()
    .collect(batchBySize(sizeThreshold));

关键注意点

  • 必须保证FileInfo类提供getFileSize()的getter方法,否则无法获取文件大小;
  • 若单个文件的fileSize超过阈值,该文件会单独成为一个子列表;
  • 并行流场景下,combiner方法会正确合并不同线程的批次,确保最终结果符合阈值规则;
  • 该实现通过Collector封装状态,避免了外部状态修改的线程安全问题,符合Stream规范。

内容的提问来源于stack exchange,提问作者Neha

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 06:52:26