Java Iterator实现 - next()和hasNext()强制执行命令

Dan*_*Dan 8 java concurrency iterator

我有一个实现java.util.Iterator要求next()始终通过调用来进行调用hasNext().(这是因为结果在多线程环境中异步返回,并且永远不清楚可能会有多少结果).

在JavaDoc中正确记录它是否"正确"然后抛出一个RuntimeException如果违反了它.或者这会使Iterator接口拉得太远?

所有的想法赞赏?

Fab*_*eeg 18

我可能在这里遗漏了一些东西,但为什么不在hasNext()实施中调用内部?

  • @Dan我总是试图让客户端以错误的方式使用API​​,并且我认为在调用其他东西之前要求调用某些内容会使API很容易以错误的方式使用. (11认同)
  • @Dan:迭代器在库中定义了一组特定的语义.遵守这些语义的任何用法都是正确的.如果您的语义与标准迭代器不同,那么在定义自己的迭代器时,您可能会使用户感到困惑并使您的代码变得"更难".虽然我只能同意正确的用法是在`next()`之前检查`hasNext()`,但只有在没有更多元素的情况下,来自迭代器的正确响应才会抛出`NoSuchElementException`.在强制正确性时,您不仅要求用户提供,还要求您自己实施. (3认同)
  • 不同意 - 我认为在没有先调用hasNext()的情况下调用next()是错误的.我会强制执行普遍接受的正确用法. (2认同)
  • 我想你不在这里.通常,它被接受,在大多数情况下,例程应该完成它们分配的工作,而不依赖于调用顺序.例如,如果您有一些数据对象并且您想要计算报告,请不要说API的用户应首先调用calculateReport()然后多次调用getReportColumn().相反,calculateReport应该返回一个Report-object,它允许记录报告列.同样在这里:next()应该不依赖于特殊的调用顺序,特别是因为指定你可以单独调用next(). (2认同)

uck*_*man 15

要求hasNext()在被叫之前next()违反iterator合同.你真的应该重写它,这样如果没有要返回的元素,就会next()抛出一个NoSuchElementException.

  • @Dan:因为`next()`只有两个有效结果:当没有下一个元素时,返回下一个值或抛出一个'NoSuchElementException`.既然你抛出一个异常,即使有下一个元素,你也违反了合同. (5认同)

McD*_*ell 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;
  }
Run Code Online (Sandbox Code Playgroud)

这对我来说听起来不错.我无法想象你想要next没有使用的情况hasNext- 这将是异常的一个秘诀.


编辑:

文档hasNext()说:

如果迭代具有更多元素,则返回true.(换句话说,如果next会返回一个元素而不是抛出异常,则返回true.)

对我来说,实施不违反合同.但是,我(正如Fabian Steeg暗示的那样)仍然执行next():

  public T next() {
    if(!hasNext()) {
      throw new NoSuchElementException();
    }
    T ret = next;
    next = null;
    return ret;
  }
Run Code Online (Sandbox Code Playgroud)

我的意思是,这项检查真的让你付出了什么代价?

您必须NoSuchElementException根据API合同检查并抛出一个.我相信,无论是测试!hasNext()还是next == null将满足这个标准,我都赞成前者.

如果有人抓住NoSuchElementException而不是打电话hasNext(),你可能会遇到更大的问题.