如何将对象流分块为指定大小N的列表并持续流转
将Java流分割为固定大小的块
Java标准Stream API本身没提供直接分块的方法,但可以通过自定义收集器、手动拆分或者第三方库实现,给你几个实用方案:
方案一:自定义收集器(流式处理,无需预存全部元素)
自己实现一个收集器,能在流处理过程中直接把元素按固定大小N打包成列表,不用先把整个流存到内存里:
public static <T> Collector<T, ?, Stream<List<T>>> chunked(int chunkSize) { return Collector.of( ArrayList::new, (container, item) -> { if (container.isEmpty() || container.get(container.size() - 1).size() == chunkSize) { container.add(new ArrayList<>(chunkSize)); } container.get(container.size() - 1).add(item); }, (leftContainer, rightContainer) -> { if (!leftContainer.isEmpty()) { List<T> lastLeftChunk = leftContainer.get(leftContainer.size() - 1); if (lastLeftChunk.size() < chunkSize) { rightContainer.stream().findFirst().ifPresent(firstRightChunk -> { int need = chunkSize - lastLeftChunk.size(); lastLeftChunk.addAll(firstRightChunk.subList(0, Math.min(need, firstRightChunk.size()))); if (firstRightChunk.size() > need) { leftContainer.add(firstRightChunk.subList(need, firstRightChunk.size())); } leftContainer.addAll(rightContainer.subList(1, rightContainer.size())); }); } else { leftContainer.addAll(rightContainer); } } else { leftContainer.addAll(rightContainer); } return leftContainer; }, Collection::stream ); }
使用方式:
objectStream .collect(chunked(N)) .peek(list -> { // 这里处理每个大小为N(最后一个可能更小)的列表 }) .forEach(...);
方案二:迭代器手动分块(简单直接)
如果不想写复杂的收集器,也可以先把流收集到列表,再手动拆分:
List<T> sourceList = objectStream.collect(Collectors.toList()); int chunkSize = N; for (int i = 0; i < sourceList.size(); i += chunkSize) { List<T> chunk = sourceList.subList(i, Math.min(i + chunkSize, sourceList.size())); // 处理当前块 }
注意:这种方式需要把整个流的元素先存到内存里,适合元素数量不多的场景,不然会占用过多内存。
方案三:用Guava库快速实现
如果项目里已经引入了Guava,可以直接用它的Lists.partition方法,省得自己写代码:
List<T> sourceList = objectStream.collect(Collectors.toList()); List<List<T>> chunks = Lists.partition(sourceList, N); chunks.stream() .peek(list -> { // 处理每个块 }) .forEach(...);
和方案二一样,需要先把流元素全部收集到列表中。
内容的提问来源于stack exchange,提问作者Arian
相关产品推荐
相关产品推荐

