Java 8如何将Iterator包装为指定大小的批量迭代器
这问题我之前做批量处理时也碰到过,Java 8里要把普通Iterator转成每次返回指定大小批量列表的Iterator,有几种实用的方案,根据你的场景选就行:
方法一:手动实现惰性批量Iterator(最推荐,纯Java 8原生)
如果你的迭代器元素量很大,或者不想一次性加载所有元素到内存,这种惰性实现最合适——每次调用next()才会去原迭代器中取最多batchSize个元素:
import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Objects; public class BatchIteratorUtils { public static <T> Iterator<List<T>> toBatchIterator(Iterator<T> originalIterator, int batchSize) { // 参数校验 Objects.requireNonNull(originalIterator, "Original iterator cannot be null"); if (batchSize <= 0) { throw new IllegalArgumentException("Batch size must be a positive integer"); } return new Iterator<List<T>>() { @Override public boolean hasNext() { // 直接复用原迭代器的hasNext判断 return originalIterator.hasNext(); } @Override public List<T> next() { if (!hasNext()) { throw new NoSuchElementException("No more elements in the iterator"); } List<T> batch = new ArrayList<>(batchSize); int remaining = batchSize; // 循环取元素,直到凑够批量大小或者原迭代器耗尽 while (remaining > 0 && originalIterator.hasNext()) { batch.add(originalIterator.next()); remaining--; } return batch; } }; } }
使用方式也很简单:
// 假设你有一个普通Iterator<String> Iterator<String> normalIterator = ...; // 转成每次返回5个元素的批量迭代器 Iterator<List<String>> batchIterator = BatchIteratorUtils.toBatchIterator(normalIterator, 5); while (batchIterator.hasNext()) { List<String> batch = batchIterator.next(); // 处理这批元素 processBatch(batch); }
方法二:利用Stream API实现(适合小数据量场景)
如果你的元素数量不多,愿意一次性加载到内存,也可以用Java 8的Stream配合分组来实现,但要注意这个方法会先把原迭代器的所有元素都读取到内存中,不适合大数据量:
import java.util.Iterator; import java.util.List; import java.util.Spliterators; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import java.util.stream.StreamSupport; public class StreamBatchExample { public static <T> Iterator<List<T>> toBatchIteratorViaStream(Iterator<T> originalIterator, int batchSize) { Objects.requireNonNull(originalIterator); if (batchSize <= 0) { throw new IllegalArgumentException("Batch size must be positive"); } AtomicInteger counter = new AtomicInteger(0); return StreamSupport.stream( Spliterators.spliteratorUnknownSize(originalIterator, 0), false // 并行流可能打乱顺序,这里用串行 ) .collect(Collectors.groupingBy(element -> counter.getAndIncrement() / batchSize)) .values() .iterator(); } }
方法三:借助第三方库(如Guava)
如果你的项目已经引入了Guava库,那直接用现成的工具类就行,省心又靠谱:
import com.google.common.collect.Iterators; import java.util.Iterator; import java.util.List; // 一行代码搞定 Iterator<List<String>> batchIterator = Iterators.partition(normalIterator, 5);
这个方法的实现也是惰性的,和我们手动写的第一种方案逻辑类似,不用重复造轮子。
内容的提问来源于stack exchange,提问作者Vlad K
相关产品推荐
相关产品推荐

