15

从 Java 5 开始,我们有了java.lang.Iterable可以在 foreach 循环中使用的新类型:

for (Object element : iterable);

Iterable合约没有指定iterator()在处理 Iterable 之前是否可以多次调用它的方法。即,尚不清楚以下内容是否适用于所有人Iterables

for (Object element : iterable);
for (Object element : iterable);

例如,一个Iterator包装实现不能被使用两次:

public class OneShotIterable<T> implements Iterable<T> {
    private final Iterator<T> it;

    public OneShotIterable(Iterator<T> it) {
        this.it = it;
    }

    @Override
    public Iterator<T> iterator() {
        return it;
    }
}

对于大多数人来说Iterables,这无关紧要,因为它们实际上是经过改造的 Collection API 类型,例如List, Set,它们的iterator()方法已经有了明确定义的契约。

我的问题是:我的OneShotIterable实施是否违反了我忽略的某些合同?换句话说,用户会Iterable期望它是可重用的吗?如果是这样,Java 5 专家组是否有“官方”建议如何处理这种“一次性” (例如在第二次调用时Iterables抛出)?IllegalStateException

4

2 回答 2

16

我可以在标准库中找到的一个先例是DirectoryStream接口。

它的 Javadoc 包含以下段落(强调他们的):

虽然DirectoryStreamextends Iterable,它不是通用的Iterable,因为它只支持一个Iterator; 调用该iterator方法以获取第二个或后续迭代器 throws IllegalStateException

对我来说,这表明了两件事:

  • 隐含的合同Iterable是您应该能够多次迭代(甚至可能同时进行!)
  • 文档中的粗体警告加上抛出IllegalStateException可能是处理您自己的类/接口中不合规的最佳方法。
于 2013-04-03T08:03:55.073 回答
1

不是我的问题的真正答案,但 Apache Commons Collections 在其IteratorUtils课程中解决了这个问题:

IteratorIterable两者都是该类型的工厂方法。上述区别清楚地表明,在包装时必须Iterators小心Iterables

于 2013-04-03T08:01:47.667 回答