几天前,我遇到了一个奇怪的错误,这个错误发生在我的地图缩减任务中。
最后,实现Iterable
接口的hadoop ValueIterable
类创建了一个迭代器实例,并在每次调用iterator()
方法时返回它。
protected class ValueIterable implements Iterable<VALUEIN> {
private ValueIterator iterator = new ValueIterator();
@Override
public Iterator<VALUEIN> iterator() {
return iterator;
}
}
这意味着,如果您在ValueIterable
上迭代一次,就无法再次迭代。
我决定查看java文档,它似乎不需要Iterable
每次都返回不同的迭代器(或者只是缺少要求?)。更深入地研究,我发现这个答案告诉我们,使用单个迭代器违反了Iterator
约定,因为它不能多次遍历集合。
这里谁是正确的?Iterable应该返回新的迭代器吗?为什么java文档不清楚?
这个hadoop类告诉客户端遍历是不可能的,正确的方法是什么?我的意思是,如果它会抛出
IllegalStateException
,它会违反Iterator#hasNext()
方法合同吗?
从这里开始:
从Iterable的迭代器()方法接收到的迭代者是特殊的。这些值可能并不都在内存中;Hadoop可能正在从磁盘进行流式传输。它们并没有真正得到Collection的支持,因此允许多次迭代是不重要的。
没有实际定义的约定规定Iterable.iterator()
返回的每个Iterator
应该重复相同的序列。这只是一种习惯,因为这是意料之中的行为。
Hadoop或任何其他库因此被允许打破这方面的规则。
java文档不清楚这到底是为了什么目的——让Iterable
的实现者有回旋余地,可以用他们想要的任何方式来做。
你应该如何做——就像链接中提到的其他答案一样——保留一个已经迭代的项目列表,以便以后重复迭代——但请注意,这可能是实时hadoop环境中的一个巨大集合,所以你很可能会崩溃。