我有一个java.util.Iterator
的实现,要求始终通过调用next()
来调用hasNext()
。 (这是因为结果是在多线程环境中异步返回的,并且永远不清楚可能会有多少结果)。
在JavaDoc中正确记录此文件是否“正确”,如果违反此规则,则抛出RuntimeException
。或者这会使Iterator界面拉得太远吗?
所有的想法都赞赏?
答案 0 :(得分:18)
我可能在这里遗漏了一些内容,但为什么不在内部调用hasNext()
?
答案 1 :(得分:15)
要求在hasNext()
之前调用next()
违反iterator
合同。你真的应该重写它,以便next()
如果没有要返回的元素,只会抛出NoSuchElementException
。
答案 2 :(得分:7)
我想你正在做这样的事情:
class IteratorImpl<T> implements Iterator<T> {
private Source<T> source = ...
private T next = null;
public boolean hasNext() {
if(next == null) {
next = source.poll();
}
return next != null;
}
这对我来说听起来不错。我无法想象你想要在没有next
的情况下使用hasNext
的情况 - 这将是异常的处方。
编辑:
hasNext()
的{{3}}说:
如果迭代有更多元素,则返回true。 (换句话说,如果next会返回一个元素而不是抛出异常,则返回true。)
对我来说,实施不违反合同。但是,我会(doc)仍然将next()
实现为:
public T next() {
if(!hasNext()) {
throw new NoSuchElementException();
}
T ret = next;
next = null;
return ret;
}
我的意思是,这项检查真的花了你多少钱?
您必须根据Fabian Steeg implies检查并抛出NoSuchElementException
。我相信,对!hasNext()
或next == null
的测试都符合此标准,但我赞成前者。
如果有人抓住NoSuchElementException
而不是致电hasNext()
,那么您可能会遇到更大的问题。
答案 3 :(得分:4)
如果您的hasNext()
和next()
来电不在同步广告/方法中,即使您在{{1}之前拨打hasNext()
,也无法保证您拥有元素}。
next()
接口的约定是如果没有更多元素,则应该抛出Iterator
。所以继续使用NoSuchElementException
方法,直到出现这种异常。
那说,看一下java.util.concurrent
包 - 它有并发集合,其迭代器可以帮助你 - 也就是说你可以使用这些集合和迭代器而不是实现自己的集合。
答案 4 :(得分:2)
当没有更多元素时,我宁愿从next()
抛出异常。在多线程环境中,hasNext()
无论如何都是无用的。
答案 5 :(得分:2)
您可以做的是自己实现Iterator
界面(如果您需要与其他API连接)并要求您的客户实施您自己更严格的界面。
我在函数式编程库中创建了这样一个类,以便在工作中的项目中轻松实现Iterator
{/ 1}}。
我的类EasierIterator实现了Iterator接口,同时要求客户端基于ResultSet
/ moveNext()
实现更简单的接口。它实际上为你做了当前项目的缓存。
答案 6 :(得分:1)
您可以执行类似下面的操作,您可以将基础数据提取委托给私有方法,并实现hasNext()
和next()
以对不存在数据做出不同反应。这样做的好处是,您可以在不先调用next()
的情况下重复调用hasNext()
,因此不会违反迭代器的合同。
public class IteratorImpl<T> implements Iterator<T> {
private final Source<T> source;
private T next;
public synchronized boolean hasNext() {
tryGetNext();
return next != null;
}
public synchronized T next() {
tryGetNext();
if (next == null) {
throw new NoSuchElementException();
}
return next;
}
private void tryGetNext() {
if (next != null) {
next = source.poll();
}
}
}
答案 7 :(得分:0)
编辑:在这个答案中,我试图争辩说这是问题所允许的。但我忽略了Iterator.hasNext
文档中的一个句子,它使我的整个推理无效:
换句话说,如果
next()
返回一个元素而不是抛出异常,则返回true。
这似乎意味着反复调用next
直到hasNext
返回true并且调用next,直到得到NoSuchElementException
应该返回相同的元素序列。
因此,问题似乎是不允许。
这是对规范律师类型答案的尝试。为清楚起见,我将以紧凑的形式重述问题:
Iterable
规范是否允许在NoSuchElementException
调用Iterator.next
时调用Iterator.hasNext
而不事先调用Iterator.hasNext
,即使元素已返回NoSuchElementException
先被叫了?
Iterator.hasNext
州的文档:
如果迭代有更多元素,则返回true。
抛出:
NoSuchElementException
- 如果迭代没有更多元素
显然,当#34;迭代没有更多元素&#34;时,它被允许抛出hasNext
,但在此之前不会。这应该与Iterator
返回false时一致。
这导致了一个问题:文档对于#34;迭代&#34;具体意味着什么?和&#34;元素&#34;? hasNext
文档没有给出答案,这为实施者提供了一些摆动空间。
在我看来,有两种可能的解释:
从迭代器接口本身的角度来看,唯一存在的概念是&#34;迭代&#34;是&#34;只要next
返回true&#34;。这意味着如果客户在hasNext
之前调用T
,他们不知道是否有更多元素,那么它是未定义的。
因此,迭代器实现者的规范允许决定迭代已经完成。所以这个问题的答案是肯定的。
但是Iterable.iterator
上的文档也提到了&#34;元素&#34;:
返回类型为
Iterable
的元素的迭代器。
那么&#34;元素&#34;这意味着什么它是否意味着&#34;实现next
的集合中的所有元素?不,它并没有这么说,并不是所有的迭代都是拥有一组固定的元素。
什么&#34;元素&#34;对于某个特定的可迭代的意思是由实施者决定。 &#34;元素的有效定义&#34;对于迭代器,可以是&#34; 集合中的所有元素,或者,客户决定在hasNext
&#34;之前调用{{1}}之前的所有元素。
因此,这个案例也得出结论,问题的答案是肯定的。 (但请看结尾处的注释!)
文档不是很清楚,但似乎问题的答案是:是的,这是允许的。
如果迭代器完成了问题,那么当然应记录该行为。但是其他的迭代也应该记录它们的迭代器是哪些元素。
例如,ArrayList.iterator
文档清楚地说明了迭代器所在的元素:
以适当的顺序返回此列表中元素的迭代器。
最后的注意事项:是的,我花了很多时间在这上面我很疯狂。