什么时候应该在Java中接受Iterable <T> vs.Collection <T>的参数?


73

在Java中使用Iterable<T>vs.有哪些注意事项Collection<T>

例如,考虑实现一种主要涉及包含Foos的集合以及一些关联的元数据的类型。这种类型的构造函数允许一次性初始化对象列表。(可以稍后设置元数据。)此构造函数应接受哪种类型?Iterable<Foo>Collection<Foo>

此决定有哪些考虑因素?

通过库类型,如下面列出的模式集合ArrayList(这可以从任何被初始化Collection,但不是一个Iterable),会导致我使用Collection<Foo>

但是为什么不接受Iterable<Foo>,因为这足以满足初始化需求?为什么Collection消费者要求的功能等级()比严格要求的功能等级(Iterable)高?


2
有一篇很棒的文章[这里] [1]。[1]:artima.com/weblogs/viewpost.jsp?thread = 119193
amischiefr

Answers:


66

许多集合类型以前都存在Iterable<T>(仅在1.5中引入)-几乎没有理由添加一个构造函数来接受Iterable<T> 以及, Collection<T>但是更改现有构造函数将是一项重大突破。

就个人而言,我会使用它Iterable<T>是否允许您做任何您想做的事情。它对调用者来说更加灵活,尤其是它使您可以使用Google Java Collections(无疑还有类似的库)进行相对容易的过滤/投影/等操作。


您说这将是“重大变化”。如果(例如)将ArrayList <T>构造函数参数从Collection <T>更改为Iterable <T>,会发生什么变化?
finnw

18
@finnw:它将是源兼容的,但不是二进制兼容的:使用当前构造函数的现有(已编译)类会中断(因为它们明确地调用Collection-param-constructor),因此需要重新编译。
圣保罗Ebermann

24

Iterable生产Iterator对象。根据Iterator定义,对象会迭代。请注意,该Iterator接口不作任何承诺,因为多少次next()之前可称为hasNext()收益false。一种Iterator可能可能遍历Integer.MAX_VALUE + 1其前值hasNext()方法返回false

但是,aCollection是的特殊形式Iterable。由于aCollection不能具有超过个Integer.MAX_VALUE元素(通过该size()方法),因此自然推定其Iterator对象不会在这么多元素上进行迭代。

因此,通过接受aCollection而不是an Iterable,您的类可以保证传递了多少个元素。如果您的类本身是a,那么这尤其可取Collection

只是我的两分钱


4
这不允许相当不合理的可迭代对象,但也要禁止不收集,完全合理的可迭代对象。
乔恩·斯基特

11
而且,实际上,aCollection也可以大于Interger.MAX_VALUE,然后size方法仅返回Integer.MAX_VALUE。a的优点Collection主要是size()方法(其他所有方法都可以在Iterator和size之上实现,如AbstractCollection所示),因此在需要在迭代之前需要大小的情况下使用Collection ,而不是仅在要迭代时使用Collection 。
圣保罗Ebermann

2
@Paŭlo:哇,我不知道Collection.size()返回的内容Integer.MAX_VALUE是否包含太多元素!
亚当·佩恩特


10

的用户Spring Data JPA将发现Repositories类型为return的集合Iterable<T>.

在我过去使用该项目进行过的项目中Spring,我发现在检索后对Collection进行操作的需求通常决定了Iterable<T>在业务层中使用它,而不是Collection<T>为了T从集合中选择Object 。

所有Collection是Iterable(即扩展Collection接口的接口,而不是Map!),因此Iterable在业务层中使用仅是按其超类型引用Collection的情况,并且仍然允许使用for-eachto进行迭代。

如果你需要操纵集合的内容,一个方便的方法可以让你来填充新的Collection,所以你可以利用的contains()remove()等与原来收集的数据。

另外,流行的第三方API(例如Google Guava和Apache Commons)为此目的提供了便利方法。


8

使用您可以使用的最通用的界面。既然您要做的就是迭代,那么我要说的Iterable是要走的路(因为它允许惰性迭代器等)。您不必关心迭代器的来源,因此不要对迭代器进行过多的限制。


4

一些构造函数,例如ArrayList(Collection c),使用Collection的toArray()方法以提高效率。


3

请参阅“为什么这么强调迭代器和可迭代对象?” 在Google收藏集常见问题解答中 可以找到喜欢使用迭代器的不错理由,尤其是在处理大量数据时。一种可能有用的类比是思考仅向前只读游标和可滚动游标之间的区别。


2

如果您要使用Collection,则只能从集合中初始化您的类,如果您要使用Iterable,则可以从collection或iterable中初始化。

由于两者的工作量和性能都将相同,因此在构造函数中接受Iterable是完全有意义的。


0

根据最不惊奇的原则,您应该模拟Java收集模式并采用Collection构造函数arg。它将使追随您的人们感到困惑。


8
我不同意-Iterable仍然允许您将Collections作为参数,但是正如John所说,它允许您传递其他类,从而使您可以遍历它们的元素。如果这是您需要的所有功能,那么它是一个更好的选择。无论如何,您的Javadocs都应该记录该论点,如果跟在您后面的人们对Java核心类感到困惑,那么可能存在更深层次的问题。;-)
Andrzej Doyle,2009年

3
我和保罗在一起。在我们自己的类或库中,我几乎看不到Iterable。我看到更多收藏,并且最频繁地列出。我认为选择Iterable背后有逻辑,但是我认为当前的惯用语是Collections。也许应该是Iterables,也许有一天,但是现在,我对Collection感到惊讶。
Carl Manaster 09年

-1

您是正确的,因为要求最通用的形式被认为是一种很好的做法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.