在Java中使用Iterable<T>
与Collection<T>
有什么注意事项?
例如,考虑实现一个主要涉及包含Foo
集合和某些关联元数据的类型。此类型的构造函数允许一次性初始化对象列表。 (可以稍后设置元数据。)此构造函数应接受哪种类型? Iterable<Foo>
或Collection<Foo>
?
这个决定有哪些考虑因素?
按照ArrayList
等库类型(可以从任何Collection
初始化,但不 Iterable
)提出的模式会引导我使用Collection<Foo>
。
但为什么不接受Iterable<Foo>
,因为这足以满足初始化需求?为什么要求消费者提供更高级别的功能(Collection
),而不是绝对必要的(Iterable
)?
答案 0 :(得分:62)
许多集合类型存在于Iterable<T>
之前(仅在1.5中引入) - 没有理由添加构造函数来接受Iterable<T>
以及 { {3}}但改变现有的构造函数将是一个重大改变。
我个人会使用Iterable<T>
,如果它允许你做你想要的一切。它对于呼叫者来说更灵活,特别是它允许您使用Google Java Collections(毫无疑问是类似的库)进行相对的简单过滤/投影/等。
答案 1 :(得分:20)
Iterable
生成Iterator
个对象。根据定义,Iterator
对象迭代。请注意,Iterator
接口不会承诺在next()
返回hasNext()
之前可以调用false
的次数。在Iterator
方法返回Integer.MAX_VALUE + 1
之前,hasNext()
可能会迭代false
个值。
但是,Collection
是Iterable
的特殊形式。由于Collection
不能超过Integer.MAX_VALUE
个元素(凭借size()
方法),因此自然会假设其Iterator
个对象不会迭代这么多元素。
因此,通过接受Collection
而不是Iterable
,您的类可以保证传入的元素数量。如果您的类本身是{{1 }}
只是我的两分钱......
答案 2 :(得分:9)
Spring Data JPA
的用户会发现类型为Repositories
Iterable<T>.
返回集合
在我过去曾使用Spring
的项目中,我发现在检索后对集合进行操作的需要通常表明在业务层中使用了Iterable<T>
而不是Collection<T>
,以便从集合中选择对象T
。
所有集合都是Iterable
(这是扩展Collection
接口的接口,因此不是Map
!),因此在业务层中使用Iterable
只是一个通过超类型引用Collection的情况,仍允许使用for-each
进行迭代。
如果您需要操作集合的内容,可以使用便捷方法填充新的Collection
,这样您就可以使用contains()
,remove()
等原始的收集数据。
或者,流行的第三方API(例如Google Guava和Apache Commons)为此提供了便利方法。
答案 3 :(得分:8)
使用最常用的界面。既然你要做的只是迭代,那么我会说Iterable
是要走的路(因为它允许惰性迭代器等)。你不关心迭代器的来源,所以不要过多限制它。
答案 4 :(得分:4)
一些构造函数,例如ArrayList(Collection c),使用Collection的toArray()方法提高效率。
答案 5 :(得分:3)
请参阅“为什么如此强调Iterators和Iterables?”在Google Collection FAQ 对于偏好迭代器的一个不错的论据,特别是在处理大量数据时。可能有帮助的一个类比是考虑仅向前只读游标和可滚动游标之间的区别。
答案 6 :(得分:2)
如果你选择Collection,那么你的类只能从一个集合初始化,如果你去Iterable,那么你可以从集合或迭代中初始化。
由于两者的努力和性能都是相同的,所以在构造函数中接受Iterable是完全合理的。
答案 7 :(得分:0)
根据最不惊讶的原则,您应该模拟Java集合模式并采用Collection构造函数arg。它会让那些追随你的人稍微不那么困惑。
答案 8 :(得分:-1)
你是对的,因为要求最一般的形式你需要的是一种良好的做法。