为范围抛出NoSuchElementException

时间:2013-07-09 04:36:17

标签: groovy iterator

假设我有以下内容(ideone):

x = [1,2,3]
y = x.iterator();

println y.next();
println y.next();
println y.next();
println y.next();

输出:

1
2
3
Caught: java.util.NoSuchElementException
java.util.NoSuchElementException
    at java_util_Iterator$next.call(Unknown Source)
    at prog.run(prog.groovy:7)

正如所料。

但是我们可以将x = [1,2,3]更改为x = 1..3,因此代码如下(ideone):

x = 1..3
y = x.iterator();

println y.next();
println y.next();
println y.next();
println y.next();

现在我们得到输出:

1
2
3
null

并没有抛出异常。为什么会这样?毫不奇怪,[1,2,3]和1..3在迭代它们时表现不同。似乎这种行为不符合iterator的合同。

有没有办法让我解决这个问题,这样的解决办法会破坏其他任何东西吗?

3 个答案:

答案 0 :(得分:0)

修改:让我试着更清楚一点:

这是Iterator类的正确用法:

x = 1..3
y = x.iterator();

while(y.hasNext()) {
    println y.next();
}

NoSuchElement异常是未经检查的(AKA运行时)异常。它没有被检查的原因是,它应该是完全可以避免的,而不依赖于异常。这与例如IOException s不同,它们被检查并且在正常使用期间更有可能发生。

在文档中没有明确说明这种方式,但是我唯一一次看到next()方法在上面正确使用迭代器时抛出NoSuchElementException就是如果你有一个<在不同步的多线程环境中进行强>可修改集合,在您调用hasNext并使用项目访问项目时,该项目已删除 next

因为Range类是不可修改的,所以这种情况不可能出现。

您不应该依赖未经检查的例外来确定项目的功能或状态。

所以,我真的认为合同没有被打破。使用迭代器的合同是在hasNext之前使用next,并且Range类的Iterator不需要因为它被错误地使用而抛出异常。

答案 1 :(得分:0)

使用:

While(y.hasNext()){
 println y.next();

}

答案 2 :(得分:0)

这是因为IntRangeIterator在距离范围结束时返回null

As you can see in the source code for it here

我想如果您觉得这是不正确的行为,您应该在邮件列表上询问,或者将错误发布到Groovy JIRA,但是因为它是been that way for 6 years我会想象它会保持这种状态(如这将是一个突破性的变化)

正如其他人所说,您应该使用foreach机制来迭代Iterator,或者如果不可能将您的来电包裹在next()中{ {1}}检查应该捕获所有你不在的情况。