java是一个“无限”迭代器——糟糕的设计?
通常认为提供Iterator
个“无限”的实现是不好的做法;i、 e.对hasNext()
的调用始终(*)返回true的位置
通常我会说“是”,因为调用代码的行为可能不稳定,但在下面的实现中hasNext()
将返回true,除非调用方从迭代器初始化时使用的列表中删除所有元素;i、 e.存在终止条件。你认为这是对Iterator
的合法使用吗?这似乎没有违反合同,尽管我想有人会说这是不直观的
public class CyclicIterator<T> implements Iterator<T> {
private final List<T> l;
private Iterator<T> it;
public CyclicIterator<T>(List<T> l) {
this.l = l;
this.it = l.iterator();
}
public boolean hasNext() {
return !l.isEmpty();
}
public T next() {
T ret;
if (!hasNext()) {
throw new NoSuchElementException();
} else if (it.hasNext()) {
ret = it.next();
} else {
it = l.iterator();
ret = it.next();
}
return ret;
}
public void remove() {
it.remove();
}
}
(学究式)编辑
一些人评论了如何使用Iterator
从无界序列(如斐波那契序列)生成值。但是,Java{
An iterator over a collection.
现在您可以认为斐波那契序列是一个无限集合,但在Java中,我将集合等同于java.util.Collection
接口,它提供了size()
等方法,这意味着集合必须是有界的。因此,使用Iterator
作为无界序列的值生成器是否合法
# 1 楼答案
这可能是语义问题,但迭代器应该努力返回下一项,而不考虑它何时结束。结尾对一个系列来说是一个副作用,尽管它可能看起来像是一个常见的副作用
不过,无限和一个10万亿物品的集合有什么区别?来电者要么想要全部,要么不想要。让来电者决定归还多少物品或何时结束
我不会说调用者不能使用for-each构造。他可以,只要他想要所有的东西
集合文档中的某些内容,比如“可能是一个无限集合”,是合适的,但不是“无限迭代器”
# 2 楼答案
一个
Iterator
的要点在于它是懒惰的,也就是说,它只给你想要的东西。如果用户要求无限Iterator
的所有对象,那是他们的问题,而不是你的问题# 3 楼答案
这是一种完全合法的使用方式-只要有适当的文档记录
使用名称
CyclicIterator
是一个好主意,因为它可以推断,如果没有正确定义循环出口情况,迭代器上的循环很可能是无限的# 4 楼答案
我认为这是完全合法的-an
Iterator
只是一连串的“东西”。为什么溪流一定要有边界许多其他语言(例如Scala)都内置了无限流的概念,并且可以对其进行迭代。例如,使用scalaz
编辑:就最小惊喜原则而言,我认为这完全取决于上下文。例如,我希望这个方法返回什么
# 5 楼答案
无限迭代器在创建无限数据时非常有用,例如Fibonacci sequence这样的线性循环序列
所以,使用这样的方法是完全可以的
# 6 楼答案
虽然我也认为这是合理的,但我想补充一点,这样的
Iterator
(或者更准确地说:一个Iterable
产生这样的Iterator
)将不能很好地与增强的for循环(也就是每个循环的a)配合使用:由于增强for循环中的代码无法直接访问迭代器,因此无法在迭代器上调用
remove()
因此,要结束循环,必须执行以下操作之一:
Iterator
的内部List
的访问权,并直接删除对象,可能会引发ConcurrentModificationException
break
退出循环Exception
退出循环return
离开循环除了最后一个选项之外,所有这些选项都不是留下增强for循环的最佳方式
“normal”for循环(或者任何其他循环加上一个显式的
Iterator
变量)可以正常工作,当然: