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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 04:25:51  来源:igfitidea点击:

Java Iterator implementation - next() and hasNext() enforcing order

javaconcurrencyiterator

提问by Dan

I have an implementation of java.util.Iteratorwhich 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 RuntimeExceptionif 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 Iteratorinterface is that NoSuchElementExceptionshould 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.concurrentpackage - 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 nextwithout 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 NoSuchElementExceptionas per the API contract. Either testing on !hasNext()or next == nullwill meet this criteria, I believe, but I would favour the former.

您必须NoSuchElementException根据API 合同检查并抛出 a 。无论是在测试!hasNext()next == null将符合这一标准,我相信,但我赞成前者。

If someone is catching NoSuchElementExceptioninstead of calling hasNext(), you probably have bigger problems.

如果有人接球NoSuchElementException而不是打电话hasNext(),您可能会遇到更大的问题。

回答by uckelman

Requiring that hasNext()be called before next()violates the iteratorcontract. You really should rewrite it so that next()simply throws a NoSuchElementExceptionif 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 Iteratorinterface 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 Iteratoraround a ResultSetin 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.hasNextdocumentation 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 nextrepeatedly until hasNextreturns true and calling next until you get a NoSuchElementExceptionshould 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 Iterablespecification to throw a NoSuchElementExceptionwhen Iterator.nextis called without a preceding call to Iterator.hasNext, even if an element would have been return had Iterator.hasNextbeen called first?

Iterable规范是否允许在没有预先调用的情况下抛出一个NoSuchElementExceptionwhen Iterator.next被调用Iterator.hasNext,即使一个元素会被 returnIterator.hasNext被首先调用?

Discussion

讨论

The documentation for Iterator.hasNextstates:

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 NoSuchElementExceptionwhen "the iteration has no more elements", but not before that. That should coincide with when hasNextreturns false.

显然,NoSuchElementException当“迭代没有更多元素”时允许抛出,但在此之前不允许抛出。这应该与hasNext返回 false时一致。

This leads to the question: Exactly what does the documentation mean with "the iteration" and "elements"? The Iteratordocumentation does not give an answer to that, which gives some wiggling space for implementers.

这就引出了一个问题:文档中的“迭代”和“元素”究竟是什么意思?该Iterator文档没有给出答案,这给实施者一些摆动的空间。

In my view there are two possible interpretations:

在我看来,有两种可能的解释:

  1. From the perspective of the iterator interface itself the only existing concept of "iteration" is "as long as hasNextreturns true". That implies that if the client calls nextbefore hasNextthey 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.

  2. But the documentation on Iterable.iteratoralso 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 nextbefore hasNext".

    So this case also leads to the conclusion that the answer to the question is yes. (But please see the note on the end!)

  1. 从迭代器接口本身的角度来看,“迭代”唯一存在的概念是“只要hasNext返回真”。这意味着如果客户端nexthasNext不知道是否有更多元素之前调用,则它是未定义的。

    因此,迭代器实现者的规范允许决定迭代已经完成。所以这个问题的答案是肯定的。

  2. 但是文档中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.iteratordocumentation 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.

最后一点:是的,我在这上面花这么多时间真是太疯狂了。