为什么Java不允许在迭代器上使用foreach(仅在迭代器上)? [英] Why does Java not allow foreach on iterators (only on iterables)?

查看:124
本文介绍了为什么Java不允许在迭代器上使用foreach(仅在迭代器上)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


可能重复:

为什么Java的Iterator不是Iterable?

给定迭代器的每个循环使用的惯用方法?

可以我们使用for-each循环来迭代Iterator类型的对象?

foreach循环据我所知在Java 5中添加了语法糖。所以

The foreach loop are as far as I know syntax sugar added in Java 5. So

Iterable<O> iterable;
for(O o : iterable) {
    // Do something
}

将基本上产生与

Iterable<O> iterable;
for(Iterator<O> iter = iterable.iterator(); iter.hasNext(); /* NOOP */) {
    O o = iter.next();
    // Do something
}

但是,如果我没有迭代首先,但只有一个迭代器(比如,因为一个类提供了两个不同的迭代器),我不能使用语法糖foreach循环。显然我仍然可以做普通的旧式迭代。但是,我真的想这样做:

However, if I do not have an iterable in the first place, but only an iterator (say, because a class offers two different iterators), I cannot use the syntax sugar foreach loop. Obviously I can still do the plain old style iteration. However, I'd actually like to do:

Iterator<O> iter;
for(O o : iter /* Iterator<O>, not Iterable<O>! */) {
     // Do something
}

当然我可以做假的 Iterable

class Adapter<O> implements Iterable<O> {
    Iterator<O> iter;

    public Adapter(Iterator<O> iter) {
        this.iter = iter;
    }

    @Override
    public Iterator<O> iterator() {
        return iter;
    }
}

(实际上这是对Iterable的丑陋滥用API,因为它只能迭代一次!)

(Which in fact is an ugly abuse of the Iterable API, as it can only be iterated once!)

如果它是围绕 Iterator 设计的,而不是可迭代的,可以做很多有趣的事情:

If it were designed around Iterator instead of iterable, one could do a number of interesting things:

for(O o : iterable.iterator()) {} // Iterate over Iterable and Collections

for(O o : list.backwardsIterator()) {} // Or backwards

Iterator<O> iter;
for(O o : iter) {
    if (o.something()) { iter.remove(); }
    if (o.something()) { break; }
}
for(O : iter) { } // Do something with the remaining elements only.

有没有人知道为什么语言是这样设计的?如果一个类同时实现 Iterator Iterable ,以避免歧义?为了避免程序员错误,假设for(O o:iter)将处理所有元素两次(并忘记获得一个新的迭代器)?或者还有其他原因吗?

Does anyone know why the language was designed this way? To avoid ambiguity if a class would implement both Iterator and Iterable? To avoid programmer errors that assume that "for(O o : iter)" will process all elements twice (and forget to get a fresh iterator)? Or is there some other reason for this?

或者是否有一些我不知道的语言技巧?

Or is there some language trick I just do not know?

推荐答案

所以我现在有一个合理的解释:

So I have a somewhat reasonable explanation now:

短版本:因为语法也适用于数组,没有迭代器。

Short version: Because the syntax also applies to arrays, which don't have iterators.

如果语法是围绕 Iterator设计的正如我提出的那样,它与数组不一致。让我给出三个变体:

If the syntax were designed around Iterator as I proposed, it would be inconsistent with arrays. Let me give three variants:

A)由Java开发人员选择:

A) as chosen by the Java developers:

Object[] array;
for(Object o : array) { }
Iterable<Object> list;
for(Object o : list) { }
Iterator<Object> iter;
while(iter.hasNext()) { Object o = iter.next(); }

行为方式相同,并且在数组和集合中高度一致
迭代器必须使用经典的迭代样式(至少不会导致错误)。

The behaves the same way and is highly consistent across arrays and collections. Iterators however have to use the classic iteration style (which at least is not likely to cause errors).

B)允许数组和迭代器

Object[] array;
for(Object o : array) { }
Iterable<Object> list;
for(Object o : list.iterator()) { }
Iterator<Object> iter;
for(Object o : iter) { }

现在数组和集合不一致;但是数组和ArrayList非常密切相关,并且应该以相同的方式运行。现在,如果在任何时候,该语言是扩展来制作,例如数组实现 Iterable ,它变得不一致。

Now arrays and collections are inconsistent; but arrays and ArrayList are very closely related and should behave the same way. Now if at any point, the language is extended to make e.g. arrays implement Iterable, it becomes inconsistent.

C)允许所有三个:

Object[] array;
for(Object o : array) { }
Iterable<Object> list;
for(Object o : list) { }
Iterator<Object> iter;
for(Object o : iter) { }

现在如果我们最终处于不明确的情况当有人实现两者 Iterable Iterator (是for循环应该得到一个新的迭代器或迭代当前 - 很容易在树状结构中发生!?!)。一个简单的tie-braker alaIterable beats Iterator遗憾的是不会这样做:它突然引入了运行时与编译时差和泛型问题。

Now if we end up in unclear situations when either someone implements both Iterable and Iterator (is the for loop supposed to get a new iterator or iterate over the current - happens easily in tree-like structures!?!). A simple tie-braker ala "Iterable beats Iterator" unfortunately won't do: it suddenly introduces runtime vs. compile time difference and generics issues.

现在突然间,我们需要注意我们是否要迭代集合/可迭代或数组,此时我们以很大的混乱为代价获得了很少的好处。

Now suddenly, we need to pay attention to whether we want to iterate over collections/iterables or arrays, at which point we have gained very little benefits at the cost of a big confusion.

方式for each在Java(A)中是非常一致的,它会导致很少的编程错误,并且它允许将来将数组转换为常规对象的可能性。

The way "for each" is in Java (A) is very consistent, it causes very little programming errors, and it allows for the possible future change of turning arrays into regular objects.

有一个变种 D)可能也可以正常工作:
for-each仅用于迭代器。最好通过向原始数组添加 .iterator()方法:

There is a variant D) that would probably also work okay: for-each for Iterators only. Preferrably by adding a .iterator() method to primitive arrays:

Object[] array;
for(Object o : array.iterator()) { }
Iterable<Object> list;
for(Object o : list.iterator()) { }
Iterator<Object> iter;
for(Object o : iter) { }

但这需要更改运行时环境,而不仅仅是编译器,并打破向后兼容性。另外,上述混淆仍然存在

But this requires changes to the runtime environment, not just the compiler, and breaks backwards compatibility. Plus, the mentioned confusion is still present that

Iterator<Object> iter;
for(Object o : iter) { }
for(Object o : iter) { }

仅迭代数据一次。

这篇关于为什么Java不允许在迭代器上使用foreach(仅在迭代器上)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆