【问题标题】:Iterable: may iterator() returns null in case there is nothing to iterate over?可迭代:如果没有可迭代的内容,iterator() 是否可以返回 null?
【发布时间】:2014-07-28 14:56:49
【问题描述】:

一个实现Iterable接口的对象必须有一个带有这个签名的方法:

Iterator<T> iterator()

作为Iterable,这段代码安全吗?

while(o.iterator().hasNext()) { ... }

换句话说,iterator() 是否可以返回 null 以防没有可迭代的内容?

编辑:

1- 正如你们中的一些人所指出的,每次执行 o.iterator() 时返回的迭代器都是不同的。很公平!我必须承认我在写问题时忘记了这一点。

假设这一行被重写:

Iterator<String> it = o.iterator();
....
....
while(it.hasNext() {...}

2- 正如你们中的一些人所指出的,当 Iterable.iterator() 的文档说:“返回一组 T 类型元素的迭代器”时,返回 null 是一种不好的编程习惯。

但是,我的问题是 Java API 文档中的某些“合同”是否直接或间接地阻止了返回 null。对我来说,“在一组 T 类型的元素上返回一个迭代器”并不能阻止返回 null。我可能错了。

您的回答和其他研究得出的结论

总体而言:Java API 无法说明迭代器值是否为 null,除非在文档中明确说明。在这种情况下,没有说明任何内容,但是可以认为 Java API 方法永远不会返回 null 迭代器值。对于个人编写的 API,这可能会有所不同。

  • 文档中没有任何内容阻止返回值为 null(例如 @NotNull)
  • 在 Javadoc 中,许多 @Return 是显式的,而 null 也是预期的
  • This question 是关于一般的空返回值,很有趣。
  • 我发现 an attempt 是一种描述 API 的语言,尽管它适用于 .NET

【问题讨论】:

  • 你为什么在循环中调用o.iterator()?只需获取一次,只需先致电hasNext()
  • Not according to the docs。 (显然,这并不能阻止某人编写确实返回null的实现,但这会违反接口。)
  • 文档说:在一组 T 类型的元素上返回一个迭代器。没有关于 null 的排除。
  • @mins null 不是一组元素的迭代器。
  • null included 也没有。 JDK Javadoc 中到处都是@return 标记,这些标记指定可以返回null。如果在这种情况下不存在,那么您无论如何都无权承担它。

标签: java null iterator


【解决方案1】:

如果没有可迭代的内容,iterator() 可能会返回 null

null 可能会被返回(Java 中没有工具可以阻止您这样做),但永远不应该。而是返回 hasNext() 方法返回 false 的迭代器。

您需要知道Iterable 对象的用途是与for-each 循环一起使用

for (Type item : IterableInstance){
    //handle 'item'
    System.out.println(item);
}

which is translated to something like

for(Iterator<Type> i = someList.iterator(); i.hasNext(); ) {
    Type item = i.next();

    //handle 'item'
    System.out.println(item);
}

因此,如果iterator() 返回null,您将在i.hasNext() 处获得NullPointerException(因为i 将保持null)。为了避免 NPE,您需要适当的迭代器实例,hasNext() 将返回 false(如果没有要迭代的元素)。这将防止循环迭代。


除了您的代码中存在其他问题的形式

while(o.iterator().hasNext()) { ... }

您在这里所做的是每次检查条件时都会创建 新迭代器,因为您正在调用 o.iterator(),它将从第一个元素开始迭代。换句话说,您每次都检查第一个元素是否存在,如果o 不为空,则可能导致无限循环。

你需要的是

Iterator<SomeType> it = o.iterator();
while(it.hasNext()) { ... }

【讨论】:

  • 谢谢。这似乎是完整的答案。关于每次评估迭代器的新实例:同意,但是假设这一行被重写:while(it.hasNext(){...},它已被分配一次。您能否为您的陈述提供参考?
  • 我不确定你想找到什么样的参考资料。纯粹的逻辑似乎足以说明 null 永远不应该作为 iterator() 的结果返回。你需要知道Iterable对象主要用于for-each循环(for(T element : IterableInstance))。如果您要实现iterable(),您是否希望使用您的代码的人每次在for-each 中使用它时也必须处理NullPointerException
  • @mins 换句话说,返回null 是允许的(没有阻止它的机制),但这是非常糟糕的设计,不应该使用它。例如,来自 Collection 框架的类(ArrayListHashSet、..,)永远不会返回 null。您可以通过查看他们的源代码来检查它。
  • 是的,这就是我的意思......你说的有道理,但我找不到任何说返回的迭代器不允许为空的“合同”。对于返回 Iterator 的方法,null 不是无效的返回值,对吧?
【解决方案2】:

换句话说,如果没有可迭代的内容,iterator() 可以返回 null 吗?

没有。 Iterable 接口的正确 实现永远不会从其iterator() 方法返回null。它将返回一个非空的Iterator,其hasNext() 方法立即返回false

但是:

这段代码安全吗?

当然可以,但它并没有像你想象的那样做,因为iterator() 的约定是每次调用iterator() 时都返回一个不同的迭代器。

【讨论】:

  • iterator() 每次返回不同的实例,ok。我已经编辑了我的问题。您是否有一些参考来支持您关于 null 不允许的答案?据我所知 null 是返回类型 Iterator? 的有效值
  • 是的,在某种意义上,null 是任何引用类型的有效“值”。但是,正如我在上面已经评论过的,null 不是一组元素的迭代器,这是Iterable#iterator() 方法的JavaDoc 所说的它返回的内容。
猜你喜欢
  • 1970-01-01
  • 2015-07-23
  • 2014-11-27
  • 2011-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-23
  • 1970-01-01
相关资源
最近更新 更多