Java 迭代器实现 - next() 和 hasNext() 强制执行顺序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2176212/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java Iterator implementation - next() and hasNext() enforcing order
提问by Dan
I have an implementation of java.util.Iterator
which requires that the call to next()
should always be proceeded by a call to hasNext()
. (This is because results are returned asynchronosly in a multi threaded environment and it is never clear how many more results there might be).
我有一个实现,java.util.Iterator
它要求调用 tonext()
应始终通过调用hasNext()
. (这是因为在多线程环境中结果是异步返回的,并且永远不清楚可能还有多少结果)。
Would it be 'correct' to properly document this in the JavaDoc and then throw a RuntimeException
if this was violated. Or is this stretching the Iterator interface a little too far?
在 JavaDoc 中正确记录这一点是否“正确”,RuntimeException
如果违反了,则抛出一个。或者这是否将 Iterator 接口拉伸得太远了?
All thoughts appreciated?
所有的想法都赞赏?
采纳答案by Fabian Steeg
I might be missing something here, but why not call hasNext()
internally in your implementation?
我可能在这里遗漏了一些东西,但为什么不在hasNext()
你的实现中内部调用呢?
回答by Bozho
If your hasNext()
and next()
calls aren't in a synchronized block/method, it is not guaranteed that you will have elements even if you call hasNext()
before next()
.
如果您的hasNext()
andnext()
调用不在同步块/方法中,即使您调用hasNext()
before ,也不能保证您将拥有元素next()
。
The contract of the Iterator
interface is that NoSuchElementException
should be thrown if there are no more elements. So proceed with the next()
method until such an exception arises.
Iterator
接口的约定是NoSuchElementException
如果没有更多元素应该抛出。所以继续这个next()
方法,直到出现这样的异常。
That said, take a look at the java.util.concurrent
package - it has concurrent collections whose iterators may help you - i.e. you can use these collections and iterators instead of implementing your own.
也就是说,看看这个java.util.concurrent
包 - 它有并发集合,其迭代器可以帮助你 - 即你可以使用这些集合和迭代器而不是实现你自己的。
回答by Joonas Pulakka
I would rather throw an exception from next()
, when there are no more elements. In a multi-threaded environment hasNext()
is pretty useless anyway.
next()
当没有更多元素时,我宁愿从 抛出异常。hasNext()
无论如何,在多线程环境中是非常无用的。
回答by McDowell
I imagine you're doing something like this:
我想你正在做这样的事情:
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;
}
That sounds OK to me. I can't imagine a situation where you'd want to use next
without hasNext
- it would be a recipe for exceptions.
这对我来说听起来不错。我无法想象您想在没有的情况下使用的next
情况hasNext
- 这将是例外的秘诀。
EDIT:
编辑:
The docfor hasNext()
says:
该文档的hasNext()
说:
Returns true if the iteration has more elements. (In other words, returns true if next would return an element rather than throwing an exception.)
如果迭代有更多元素,则返回 true。(换句话说,如果 next 将返回一个元素而不是抛出异常,则返回 true。)
To me, the implementation does not violate the contract. However, I would (as Fabian Steeg implies) still implement next()
as:
对我来说,实施并不违反合同。但是,我会(正如Fabian Steeg 暗示的那样)仍然实现next()
为:
public T next() {
if(!hasNext()) {
throw new NoSuchElementException();
}
T ret = next;
next = null;
return ret;
}
I mean, what does that check really cost you?
我的意思是,那张支票到底花了你多少钱?
You must check and throw a NoSuchElementException
as per the API contract. Either testing on !hasNext()
or next == null
will meet this criteria, I believe, but I would favour the former.
您必须NoSuchElementException
根据API 合同检查并抛出 a 。无论是在测试!hasNext()
或next == null
将符合这一标准,我相信,但我赞成前者。
If someone is catching NoSuchElementException
instead of calling hasNext()
, you probably have bigger problems.
如果有人接球NoSuchElementException
而不是打电话hasNext()
,您可能会遇到更大的问题。
回答by uckelman
Requiring that hasNext()
be called before next()
violates the iterator
contract. You really should rewrite it so that next()
simply throws a NoSuchElementException
if there is no element to return.
要求hasNext()
在之前被调用是next()
违反iterator
合同的。您真的应该重写它,以便在没有要返回的元素时next()
简单地抛出 a NoSuchElementException
。
回答by Adamski
You could do something similar to the below, whereby you delegate the underlying data fetch to a private method, and implement hasNext()
and next()
to react differently to the absence of data. This has the advantage that you can repeatedly call next()
without calling hasNext()
first, and hence do not violate the contract of Iterator.
您可以执行与以下类似的操作,将底层数据获取委托给私有方法,并在缺少数据的情况下实现hasNext()
并next()
做出不同的反应。这样做的好处是next()
无需hasNext()
先调用就可以重复调用,因此不会违反 Iterator 的约定。
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();
}
}
}
回答by Vincent Robert
What you can do is implement the Iterator
interface yourself (if you need to interface with other API) and ask your clients to implement your own stricter interface.
您可以做的是Iterator
自己实现接口(如果您需要与其他 API 接口)并要求您的客户实现您自己的更严格的接口。
I created such a class in my functional programming library in order to easily implement an Iterator
around a ResultSet
in a project at work.
我在函数式编程库为了创建这样的类很容易地实现一个Iterator
围绕ResultSet
在工作的项目。
My class EasierIteratorimplements the Iterator interface while requiring that the client implements a simpler interface based on moveNext()
/getCurrent()
. It actually does the caching of the current item for you.
我的类EasierIterator实现了 Iterator 接口,同时要求客户端实现基于moveNext()
/的更简单的接口getCurrent()
。它实际上为您缓存当前项目。
回答by Lii
EDIT:In this answer I tried to argue that it is allowed what the question asks about. But I overlooked one sentence in the Iterator.hasNext
documentation which invalidates my whole reasoning:
编辑:在这个答案中,我试图争辩说允许问题询问什么。但是我忽略了Iterator.hasNext
文档中的一句话,这使我的整个推理无效:
In other words, returns true if
next()
would return an element rather than throwing an exception.
换句话说,如果
next()
会返回一个元素而不是抛出异常,则返回 true 。
This seems to imply that calling next
repeatedly until hasNext
returns true and calling next until you get a NoSuchElementException
should return the same sequence of elements.
这似乎意味着next
重复调用直到hasNext
返回 true 并调用 next 直到你得到 aNoSuchElementException
应该返回相同的元素序列。
Thus it seems that what the question asks about is notallowed.
这样看来,这个问题问怎么样是不会允许的。
Original answer
原答案
This is an attempt on a specification lawyer type of answer. For clarity I'll restate the question in a compact form:
这是对规范律师类型答案的尝试。为了清楚起见,我将以紧凑的形式重申这个问题:
Is it allowed by the
Iterable
specification to throw aNoSuchElementException
whenIterator.next
is called without a preceding call toIterator.hasNext
, even if an element would have been return hadIterator.hasNext
been called first?
Iterable
规范是否允许在没有预先调用的情况下抛出一个NoSuchElementException
whenIterator.next
被调用Iterator.hasNext
,即使一个元素会被 returnIterator.hasNext
被首先调用?
Discussion
讨论
The documentation for Iterator.hasNext
states:
Iterator.hasNext
状态的文档:
Returns true if the iteration has more elements.
如果迭代有更多元素,则返回 true。
And for Iterator.next
:
而对于Iterator.next
:
Throws:
NoSuchElementException
- if the iteration has no more elements
抛出:
NoSuchElementException
- 如果迭代没有更多元素
Apparently it's allowed to throw NoSuchElementException
when "the iteration has no more elements", but not before that. That should coincide with when hasNext
returns false.
显然,NoSuchElementException
当“迭代没有更多元素”时允许抛出,但在此之前不允许抛出。这应该与hasNext
返回 false时一致。
This leads to the question: Exactly what does the documentation mean with "the iteration" and "elements"? The Iterator
documentation does not give an answer to that, which gives some wiggling space for implementers.
这就引出了一个问题:文档中的“迭代”和“元素”究竟是什么意思?该Iterator
文档没有给出答案,这给实施者一些摆动的空间。
In my view there are two possible interpretations:
在我看来,有两种可能的解释:
From the perspective of the iterator interface itself the only existing concept of "iteration" is "as long as
hasNext
returns true". That implies that if the client callsnext
beforehasNext
they doesn't know if there are more elements, it's undefined.It is hence allowed by the specification for the iterator implementer to decide that the iteration has finished. So the answer to the question is yes.
But the documentation on
Iterable.iterator
also mention "elements":Returns an iterator over elements of type
T
.So what does "elements" mean here? Does it mean "all elements in the collection implementing
Iterable
? No, it doesn't say so, and not all iterables even havea fixed set of elements.What "elements" mean for some particular iterable is left for the implementer to decide. A valid definition of "elements" for an iterator could be "all of the elements in the collection, OR, all elements before the client decides to call
next
beforehasNext
".So this case also leads to the conclusion that the answer to the question is yes. (But please see the note on the end!)
从迭代器接口本身的角度来看,“迭代”唯一存在的概念是“只要
hasNext
返回真”。这意味着如果客户端next
在hasNext
不知道是否有更多元素之前调用,则它是未定义的。因此,迭代器实现者的规范允许决定迭代已经完成。所以这个问题的答案是肯定的。
但是文档中
Iterable.iterator
也提到了“元素”:返回类型为元素的迭代器
T
。那么这里的“元素”是什么意思呢?这是否意味着“集合中的所有元素都实现了
Iterable
?不,它没有这么说,而且并非所有可迭代对象甚至都有一组固定的元素。“元素”对于某些特定的可迭代对象意味着什么由实现者决定。迭代器的“元素”的有效定义可以是“集合中的所有元素,或客户端决定调用
next
之前的所有元素hasNext
”。所以这个案例也得出了这个问题的答案是肯定的结论。(但请参阅最后的注释!)
Conclution
结论
The documentation is not really clear, but it seem like the answer to the question is: Yes, this is allowed.
文档不是很清楚,但问题的答案似乎是:是的,这是允许的。
Note
笔记
In case that an iterator does what the question asks about that behaviour should be documented of course. But other iterables should also document over which elements their iterators are.
如果迭代器执行了问题所要求的行为,当然应该记录下来。但是其他迭代器也应该记录它们的迭代器是哪些元素。
For example, the ArrayList.iterator
documentation clearly states whichelements the iterator is over:
例如,ArrayList.iterator
文档清楚地说明了迭代器结束了哪些元素:
Returns an iterator over the elements in this list in proper sequence.
以适当的顺序返回此列表中元素的迭代器。
Final note: Yes, I am crazy to spend so much time on this.
最后一点:是的,我在这上面花这么多时间真是太疯狂了。