Iterable 接口是不是有关于多次使用的官方合同?

Posted

技术标签:

【中文标题】Iterable 接口是不是有关于多次使用的官方合同?【英文标题】:Is there any official contract for the Iterable interface with respect to multiple usage?Iterable 接口是否有关于多次使用的官方合同? 【发布时间】:2013-03-24 18:54:37 【问题描述】:

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

for (Object element : iterable);

Iterable 合约没有指定在处理 Iterable 之前是否可以多次调用其iterator() 方法。即,尚不清楚以下内容是否适用于所有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 类型,例如 ListSet,它们已经为它们的 iterator() 方法定义了明确的合约。

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

【问题讨论】:

难道你不能在每次调用 iterator() 时增加 OneShotIterable 的一个字段,如果它是 gte n 则抛出异常? @LukasEder doh 你把它编辑掉了 【参考方案1】:

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

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

虽然DirectoryStream 扩展了Iterable,但它不是通用的Iterable,因为它只支持单个Iterator;调用iterator 方法来获取第二个或后续迭代器会抛出IllegalStateException

对我来说,这意味着两件事:

Iterable 上的隐含合同是您应该能够多次迭代(甚至可能同时进行!) 文档中的粗体警告加上 IllegalStateException 可能是处理您自己的类/接口中不合规的最佳方法。

【讨论】:

【参考方案2】:

并不是我的问题的真正答案,但 Apache Commons Collections 已在其 IteratorUtils 类中解决了此问题:

IteratorUtils.asIterable(Iterator) IteratorUtils.asMultipleUseIterable(Iterator)

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

【讨论】:

以上是关于Iterable 接口是不是有关于多次使用的官方合同?的主要内容,如果未能解决你的问题,请参考以下文章

请问java中的Iterator和Iterable有些啥区别啊?

关于迭代器接口的问题

006 Java集合浅析1

扩展Iterable的Haxe接口

微信小程序wx.getLocation的接口审核多次被拒经验总结

关于Collection接口和Map