我有一个包含大量元素的列表。处理此列表时,在某些情况下,我希望将列表分区为较小的子列表,在某些情况下,我希望处理整个列表。
private void processList(List<X> entireList, int partitionSize)
{
Iterator<X> entireListIterator = entireList.iterator();
Iterator<List<X>> chunkOfEntireList = Iterators.partition(entireListIterator, partitionSize);
while (chunkOfEntireList.hasNext()) {
doSomething(chunkOfEntireList.next());
if (chunkOfEntireList.hasNext()) {
doSomethingOnlyIfTheresMore();
}
}
我使用com.google.common.collect.Iterators创建分区。文件链接here 因此,在我想要将大小为100的列表分区的情况下,我调用
processList(entireList, 100);
现在,当我不想创建列表的块时,我想我可以将Integer.MAX_VALUE作为partitionSize传递。
processList(entireList, Integer.MAX_VALUE);
但这会导致我的代码内存不足。有人可以帮我吗?我错过了什么?什么是迭代器在内部做什么,我该如何克服这个问题?
编辑:我还需要&#34;如果&#34;只有在需要处理更多列表时,才能执行某些操作。即我需要迭代器的hasNext()函数。
答案 0 :(得分:6)
由于Iterators.partition()
在内部填充具有给定分区长度的数组,因此会出现内存不足错误。分配的数组始终是分区大小,因为在迭代完成之前,不知道实际的元素数。 (如果他们在内部使用了ArrayList
,问题可能会被阻止;我想设计师们认为数组在常见情况下会提供更好的性能。)
使用Lists.partition()
可以避免此问题,因为它委托给List.subList()
,它只是基础列表的视图:
private void processList(List<X> entireList, int partitionSize) {
for (List<X> chunk : Lists.partition(entireList, partitionSize)) {
doSomething(chunk);
}
}
答案 1 :(得分:0)
通常在分区时,它会使用给定的partitionSize分配一个新列表。所以在这种情况下很明显会出现这样的错误。当您只需要单个分区时,为什么不使用原始列表。可能的解决方案。
chunkOfEntireList
,。答案 2 :(得分:0)
假设您尝试通过并行处理列表的块来解决并行问题,那么最好将MapReduce或Spark视为包含流程管理的更大框架。
但是,作为单一应用程序的一部分,您可以考虑它的节点本地变体 - 包括Java 8 Streams。请注意List<X>
上提供的parallelStream()
方法。