4

我正在研究 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
}

这增加了实现 custom 的开销iterator

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

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

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


更新

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

4

3 回答 3

7

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

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

于 2012-03-02T09:11:18.547 回答
4

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

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

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

于 2012-03-02T09:13:57.337 回答
2

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

Iterable<String> values = ... // typically a Collection (List, Set...)

for (String value : values) {
    // do something with the value
}

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

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

于 2012-03-02T09:34:20.987 回答