在方法中返回可迭代对象是否是不良实践?

10

我经常在很多地方看到,应该避免返回一个iterable而应该返回一个collection。例如 -

public Iterable<Maze> Portals() {     
    // a list of some maze configurations
    List<Maze> mazes = createMazes();
    ...
    return Collections.unmodifiableList(mazes);
}

返回一个iterable只有在使用foreach循环时才有用,而collection已经提供了一个iterator并且提供了更多的控制。请问什么情况下特别返回iterable会有益呢?或者我们应该总是返回collection呢?

注意:这个问题与Guava库无关。

4个回答

15

当我们需要延迟加载包含大量元素的集合时,返回一个Iterable会很有益。

Google Collections FAQ中的以下引用似乎支持懒加载的想法:

为什么如此强调迭代器和可迭代对象?

通常情况下,当一个Iterable或Iterator可以胜任时,我们的方法不需要传递一个Collection。这个区别对我们来说非常重要,因为在Google有时候我们需要处理非常大量的数据,这些数据可能过大而无法在内存中存储,但可以在某些计算过程中从头到尾遍历。这样的数据结构可以实现为集合,但它们的大多数方法都必须抛出异常、返回错误答案或表现非常差。对于这些情况,Collection是不适合的,就像一个方块塞进圆洞一样。

一个Iterator代表了一个单向滚动的"流"元素,而一个Iterable是任何可以生成独立迭代器的东西。一个Collection比这还要多得多,所以只有当我们需要时才使用它。


2
我可以看到优点和缺点:
  • 一个优点是IterableCollection更简单。如果您有一种非标准的集合类型,将其设置为Iterable可能比设置为Collection更容易。实际上,有些类型的集合对于实现某些Collection方法是有问题的。例如,惰性集合类型和您不想依赖标准的equals(Object)方法来确定成员身份的集合。

  • 一个缺点是Iterable的功能较少。如果您有一个实现了Collection的具体类型,并将其作为Iterable返回,则会删除代码直接调用各种有用的集合方法的可能性。

  • 有些情况下,既不适合使用Iterable也不适合使用Collection;例如,原始类型的专业集合...在这些集合中,需要避免使用原始包装类型的开销。

您无法真正说返回Iterable是好还是坏的做法。它取决于情况;例如,您正在设计的API的目的以及您想/需要对其施加的要求或限制。


1
问题在于,如果基础集合发生更改,那么你将会遇到麻烦。 如果你正在使用一个会抛出“concurrentmodification”异常的集合,那么你也需要注意它,但是使用集合就没有这样的问题。

这没有任何意义。不管是在 Iterable 还是在 Collection 引用中保持,基础集合实现仍然是相同的。 - SimonC
@SimonC:考虑这样一种情况,我向用户返回一个可迭代对象,他开始使用它来遍历集合,但在他遍历的过程中,另一个用户改变了该集合。那么用户会得到异常,对吧?现在明白了吗? - Lokesh
我知道你想表达什么,但是如果被修改的集合以Iterable类型的变量或Collection类型的变量保存,同样的事情仍会发生。被修改的集合仍然是相同的具体类型。 - SimonC
1
@SimonC:我的观点是,如果你有集合,那么你总是可以选择遍历而不使用迭代器,从而避免并发修改异常。如果你传递迭代器,那么你就没有选择余地了。 - Lokesh
好的,我现在明白你的意思了。然而,ConcurrentModificationException 表示编程错误。如果你知道另一个线程可能会修改集合,你不应该有意地访问它,除非进行某种形式的同步。使用 Collection 上的方法来访问正在被另一个线程修改的集合可能避免抛出异常,但行为是不可预测的。 - SimonC

1
返回最具体的类型,以便于问题的使用。例如,如果您有一个创建新集合的方法,或者可以轻松地将集合包装在不可修改的包装器中,则将集合作为CollectionListSet返回,可以使客户端开发人员的工作更加容易。
对于可能在运行时生成值的代码,返回Iterable是有意义的;例如,您可以想象一个生成斐波那契数列的生成器,它创建了一个Iterator来计算下一个数字,而不是尝试存储某个查找表。如果您正在编写框架或接口代码,其中这种“流式”API可能很有用(Guava及其功能类做了大量这方面的工作),那么指定Iterable而不是集合类型可能值得在消费者方面牺牲一些灵活性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接