我试图使用迭代器中的迭代次数作为计数器,但是想知道这样做的后果。
private int length(Iterator<?> it) {
int i = 0;
while(it.hasNext()) {
it.next();
i++;
}
return i;
}
这很好用,但我担心迭代器可能会在幕后做什么。也许当我在堆栈上迭代时,它会弹出堆栈中的项目,或者如果我使用优先级队列,它会修改优先级。
javadoc说这是关于iterator:
下
E next()
返回迭代中的下一个元素 返回:
迭代中的下一个元素
抛出:
NoSuchElementException - 如果迭代没有更多元素
我没有看到保证迭代这个未知的集合不会修改它。我是在考虑不切实际的边缘情况,还是这是一个问题?还有更好的方法吗?
答案 0 :(得分:5)
Iterator
只是为某种流提供了一个接口,因此next()
不仅可以以某种方式破坏数据,而且甚至可以对{{1}中的数据进行破坏。 1}}是唯一且不可替代的。
我们可以提出更直接的示例,但一个简单的示例是DirectoryStream
中的Iterator
。虽然Iterator
在技术上是DirectoryStream
,但它只允许构建一个Iterable
,因此如果您尝试执行以下操作:
Iterator
您将在foreach块中获得异常,因为该流只能迭代一次。总而言之,您的Path dir = ...
try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
int count = length(stream.iterator());
for (Path entry: stream) {
...
}
}
方法可能会更改对象并丢失数据。
此外,没有理由length()
必须与某个单独的数据存储相关联。以answer I gave a few months之前的例子为例,提供一种选择Iterator
随机数的简洁方法。通过使用无限n
,我们能够懒惰地提供,过滤和传递任意大量的随机数据,无需一次性存储,甚至计算它们直到需要它们。因为Iterator
不支持任何数据结构,所以查询它显然具有破坏性。
现在说,这些例子不会让你的方法变坏。请注意,Guava library(每个人都应该使用)提供了一个Iterators
类,其中包含您在上面详述的行为,称为size()
以符合集合框架。然后,这些方法的用户需要知道他们正在使用什么类型的数据,并避免进行不小心的调用,例如尝试计算他们知道不能的Iterator
中的结果数量。替换。
答案 1 :(得分:4)
据我所知,Collection
规范并未明确声明迭代集合不会修改它,但标准库中没有类显示该行为(实际上至少有一个,见dimo414's answer),所以任何上课的人都会非常怀疑。我认为你不必担心这个。
请注意,Guava
库以与您相同的方式实现Iterators.size()和Iterables.size(),因此很明显他们在一般情况下会发现它是安全的。
答案 2 :(得分:2)
不,迭代集合不会修改集合。 Iterator
类确实有remove()
方法,这是在迭代期间从集合中删除元素的唯一安全方法。但只是调用hasNext()
和next()
不会修改集合。
请注意,如果您修改next()
返回的对象,则这些更改将出现在您的收藏中。
答案 3 :(得分:0)
考虑一下 - 返回事物的方法(如果它们被正确编写)访问器方法,意味着它们只返回数据。他们不修改它(它们不是mutator方法)。
这是我在磁盘上有关如何实现迭代器的示例。如您所见,实际上没有修改任何值。
public class ArraySetIterator implements Iterator
{
private int nextIndex;
private ArraySet theArraySet;
public ArraySetIterator (ArraySet a)
{
this.nextIndex = 0;
this.theArraySet = a;
}
public boolean hasNext ()
{
return this.nextIndex < this.theArraySet.size();
}
public Object next()
{
return this.theArraySet.get(this.nextIndex++);
}
}