Java迭代器实现-next()和hasNext()强制执行顺序
我有一个Java迭代器实现-next()和hasNext()强制执行顺序,java,concurrency,iterator,Java,Concurrency,Iterator,我有一个java.util.Iterator的实现,它要求对next()的调用总是通过调用hasNext()来进行。(这是因为在多线程环境中,结果是异步返回的,并且永远不清楚还会有多少结果) 在JavaDoc中正确地记录这一点是否“正确”,如果违反了这一点,则抛出运行时异常。或者这是不是将迭代器接口拉伸得太远了 所有的想法都很受欢迎?我可能在这里遗漏了一些东西,但是为什么不在实现中内部调用hasNext()?如果hasNext()和next()调用不在同步块/方法中,即使调用hasNext(),
java.util.Iterator
的实现,它要求对next()
的调用总是通过调用hasNext()
来进行。(这是因为在多线程环境中,结果是异步返回的,并且永远不清楚还会有多少结果)
在JavaDoc中正确地记录这一点是否“正确”,如果违反了这一点,则抛出运行时异常。或者这是不是将迭代器接口拉伸得太远了
所有的想法都很受欢迎?我可能在这里遗漏了一些东西,但是为什么不在实现中内部调用hasNext()
?如果hasNext()
和next()
调用不在同步块/方法中,即使调用hasNext(),也不能保证会有元素
在下一步()之前(
)
迭代器
接口的约定是,如果没有更多的元素,则应抛出NoTouchElementException
。因此,继续执行next()
方法,直到出现这样的异常
也就是说,看看这个包——它有并发集合,迭代器可以帮助您——也就是说,您可以使用这些集合和迭代器,而不是实现自己的集合和迭代器。如果没有更多元素,我宁愿从next()
抛出一个异常。在多线程环境中,hasNext()
无论如何都是毫无用处的。我想您正在做这样的事情:
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;
}
我是说,那张支票到底花了你多少钱
您必须根据检查并抛出一个NoTouchElementException
。要么在上测试!hasNext()
或next==null
将符合这一标准,我相信,但我倾向于前者
如果有人正在捕获NoSuchElementException
而不是调用hasNext()
,您可能会遇到更大的问题。要求在next()
之前调用hasNext()
违反了迭代器的约定。您真的应该重写它,以便next()
在没有要返回的元素时只抛出一个NoSuchElementException
。您可以执行类似于下面的操作,将底层数据获取委托给私有方法,并实现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();
}
}
}
公共类迭代器MPL实现迭代器{
私人最终来源;
私人T next;
公共同步布尔值hasNext(){
tryGetNext();
返回下一步!=null;
}
公共同步T next(){
tryGetNext();
if(next==null){
抛出新的NoTouchElementException();
}
下一步返回;
}
私有void tryGetNext(){
如果(下一步!=null){
next=source.poll();
}
}
}
您可以自己实现迭代器
接口(如果您需要与其他API接口),并要求您的客户实现自己更严格的接口
我在函数式编程库中创建了这样一个类,以便在工作项目中围绕ResultSet
轻松实现Iterator
我的类实现迭代器接口,同时要求客户端基于moveNext()
/getCurrent()
实现一个更简单的接口。它实际上为您缓存了当前项目。编辑:在这个答案中,我试图证明,问题所问的内容是允许的。但是我忽略了迭代器.hasNext
文档中的一句话,这使我的整个推理无效:
换句话说,如果next()
将返回元素而不是引发异常,则返回true
这似乎意味着反复调用next
,直到hasNext
返回true,并且调用next直到得到NoSuchElementException
都应该返回相同的元素序列
因此,问题所问的似乎是不允许的
原始答案
这是一个关于律师类型答案的尝试。为了清楚起见,我将以简洁的形式重申这个问题:
Iterable
规范是否允许在Iterator时抛出NoSuchElementException
。调用next
时不需要事先调用Iterator.hasNext
,即使如果先调用Iterator.hasNext
,也会返回元素
讨论
各国的文件:
如果迭代包含更多元素,则返回true
以及:
抛出:NoSuchElementException
-如果迭代没有更多元素
显然,当“迭代没有更多元素”时,允许抛出NoSuchElementException
,但在此之前不允许。这应该与hasNext
返回false时一致
这就引出了一个问题:文档对于“迭代”和“元素”到底意味着什么?迭代器
文档没有给出答案,这为实现者提供了一些摇摆空间
我认为有两种可能的解释:
从迭代器接口本身的角度来看,“迭代”唯一存在的概念是“只要hasNext
返回true”。这意味着,如果客户机在hasNext
之前调用next
,他们不知道是否还有更多元素,那么它是未定义的
因此,规范允许迭代器实现者确定迭代已经完成。那么答案是什么呢
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();
}
}
}