【问题标题】:what is the concept behind java iterator?java迭代器背后的概念是什么?
【发布时间】:2012-03-20 19:06:16
【问题描述】:

我正在研究javaiterator接口,不明白为什么会这样设计。

为什么java迭代器使用hasNext和next而不是将它们合并成一个方法?

这是java迭代器的典型用法

Iterator iter = //iterator from a list
while(iter.hasNext()){
    Object obj = iter.next();
    // do something to obj
}

为什么不

Iterator iter = //iterator from a list
Object obj = null;
try {
    while(true){
        obj = iter.next();
        // do something to obj
    }
} catch (NoSuchElementException e) {}

很明显,这种方法看起来很难看,但是如果next 在到达结束时返回 null 而不是抛出异常会发生什么?比代码可以简化为

Iterator iter = //iterator from a list
Object obj = null;
while((obj = iter.next()) != null){
    // do something to obj
}

这就是 Objective-C 中 NSEnumerator 的工作原理

NSEnumerator *enumerator = // from an array
while (id obj = [enumerator nextObject]) {
    // do something to obj
}

这增加了实现自定义iterator的开销。

这也使得 java 迭代器不是线程安全的。例如,一个 ArrayList 中有一个元素。两个线程同时要求该列表hasNext 的相同迭代器。两个线程都将看到true,它们将在该迭代器上调用next。因为只有一个元素,并且迭代器被询问了两次,这肯定会导致异常或错误状态。

我知道有线程安全的迭代器,但我不确定它是否能实现,但我认为很多阻塞正在发生,这使得它效率低下。

我认为问题是检查和更新不是自动发生的,我不明白为什么 java 设计了这样的iterator 接口。


更新

我看到 null 可以是一个值,所以我的方法是无效的。但是我上面提到的问题有什么可能的解决方法吗?

【问题讨论】:

  • 您是担心源代码的清晰度,还是担心调用hasNext() 然后next() 的性能成本?
  • 我正在做一个与 Java 迭代器相关的大学课程项目,所以只想了解更多信息
  • 好的。在现实世界中,源代码的清晰度几乎总是比微小的性能调整更令人担忧。在额外方法调用的成本开始成为执行时间的重要因素之前,您必须执行 糟糕 很多循环。

标签: java iterator concept


【解决方案1】:

您的提议将使集合中不可能有 null 值,因为它使用 null 作为“毒丸”来检测迭代的结束。

在极少数情况下,两个线程共享一个迭代器,您只需将其包装在某个自定义类中并同步对迭代器的访问,以使 check-then-act 操作原子化。无论如何,这是需要的,因为即使迭代器只有一种方法,支持集合(在您的示例中为 ArrayList)也不是线程安全的。

【讨论】:

  • 哦..我从没想过可以将 null 放入列表中...太习惯于用 Objective-C 的方式思考
  • +1 但我会添加第二个短句来说明原因。有两个状态然后使 next() 返回 null: null 值或没有更多元素。要解决这个问题,您必须禁止 null 作为值。
  • @FabianBarney 禁止将 null 作为值可能不是 这样 一个坏主意,请注意。我仍然不会用它来表示 Java Iterator 的结束:它违反了合同。
  • @AndrewSpencer 我同意在项目中限制null 的使用是有意义的。尽管如此,在像集合null 这样的Iterables 中确实有意义,恕我直言,一般不应禁止。想想存储在集合等中的数据库结果。
【解决方案2】:

您的第一个建议是糟糕的设计,因为它依赖于针对已知最终会发生的情况抛出和捕获异常。异常是相当昂贵的,并且仅用于通常不应发生的“异常”情况。

您的第二个建议没有考虑到Iterables 可以有空元素。

至于线程安全位,是的,标准Iterators 往往不是线程安全的,因此需要增加开销的自定义实现。大多数 Java 结构都是如此。作为JB Nizet notes,更多的是Iterable 结构在Iterator 之前是线程安全的。

【讨论】:

    【解决方案3】:

    为了提高源代码的清晰度,请使用(带有字符串集合的示例)

    Iterable<String> values = ... // typically a Collection (List, Set...)
    
    for (String value : values) {
        // do something with the value
    }
    

    我同意之前关于空边界集合、带异常的循环控制(这是一种残暴的形式)和线程安全的回复。

    在您的建议中,将集合设置为空是最不明智的做法,尤其是在您的代码中有“无空值”策略的情况下。然而,它是非常单一的 Java(编辑:并且违反了 Iterator 接口的合同),因此很容易混淆代码的未来维护者(编辑:并可能导致微妙和/或意外的错误)。

    【讨论】:

      猜你喜欢
      • 2012-04-17
      • 1970-01-01
      • 1970-01-01
      • 2011-01-15
      • 2022-01-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多