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();
        }
      }
    }