【问题标题】:When should I accept a parameter of Iterable<T> vs. Collection<T> in Java?我什么时候应该在 Java 中接受 Iterable<T> 与 Collection<T> 的参数?
【发布时间】:2010-11-12 16:29:33
【问题描述】:

在 Java 中使用 Iterable&lt;T&gt;Collection&lt;T&gt; 有哪些注意事项?

例如,考虑实现一个主要关注包含Foos 集合和一些相关元数据的类型。这种类型的构造函数允许一次性初始化对象列表。 (元数据可以稍后设置。)这个构造函数应该接受什么类型? Iterable&lt;Foo&gt;,还是Collection&lt;Foo&gt;

做出此决定的考虑因素是什么?

遵循ArrayList(可以从任何Collection,但不是Iterable)等库类型规定的模式将引导我使用Collection&lt;Foo&gt;

但是为什么不接受Iterable&lt;Foo&gt;,因为这足以满足初始化需求?为什么要求消费者提供更高级别的功能 (Collection),而不是严格必要的 (Iterable)?

【问题讨论】:

标签: java collections


【解决方案1】:

根据最小意外原则,您应该模拟 Java 集合模式并采用 Collection 构造函数 arg。它会让追随你的人稍微不那么困惑。

【讨论】:

  • 我不同意 - Iterable 仍然允许您将 Collections 作为参数,但正如 John 所说,允许您传入其他类,让您跨过它们的元素。如果这是您需要的所有功能,那么这是一个更好的选择。无论如何,您的 Javadocs 都应该记录该论点,如果追随您的人对核心 Java 类感到困惑,则可能存在更深层次的问题。 ;-)
  • 我和保罗在一起。在我们自己的类或库中,我几乎从未见过 Iterable。我看到 Collection 更多,List 最频繁。我认为选择 Iterable 背后有逻辑,但我认为当前的成语是 Collections。也许它应该是 Iterables,也许有一天会是,但现在,我不会对 Collection 感到惊讶。
【解决方案2】:

许多集合类型存在于Iterable&lt;T&gt;(仅在 1.5 中引入)之前存在 - 几乎没有理由添加一个构造函数来接受 Iterable&lt;T&gt; 以及 Collection&lt;T&gt; 但正在改变现有的构造函数将是一个重大更改。

我个人会使用Iterable&lt;T&gt;,如果它允许你做任何你想做的事情。它对调用者来说更加灵活,特别是它让您相对可以使用 Google Java 集合(当然还有类似的库)进行简单的过滤/投影/等操作。

【讨论】:

  • 你说这将是一个“重大变化”。如果(比如说)ArrayList 构造函数参数从 Collection 更改为 Iterable,会发生什么?
  • @finnw:它将是源代码兼容的,但不是二进制兼容的:使用当前构造函数的现有(编译)类会中断(因为它们显式调用 Collection-param-constructor)并且需要重新编译。
【解决方案3】:

您是对的,因为最好的做法是询问您所需要的最通用形式。

【讨论】:

    【解决方案4】:

    尽可能使用最通用的界面。因为你要做的就是迭代,所以我会说Iterable 是要走的路(因为它允许惰性迭代器等)。你并不关心迭代器来自哪里,所以不要过度限制它。

    【讨论】:

      【解决方案5】:

      如果你选择 Collection,那么你的类只能从一个集合初始化,如果你选择 Iterable,那么你可以从集合或可迭代初始化。

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

      【讨论】:

        【解决方案6】:

        Iterable 产生 Iterator 对象。 Iterator 对象,根据定义,迭代。请注意,Iterator 接口没有承诺在hasNext() 返回false 之前可以调用多少次next()Iterator 可能会在其 hasNext() 方法返回 false 之前迭代 Integer.MAX_VALUE + 1 值。

        但是,CollectionIterable 的特殊形式。因为Collection 不能有多个Integer.MAX_VALUE 元素(借助size() 方法),所以很自然地假定它的Iterator 对象不会遍历这么多元素。

        因此,通过接受 Collection 而不是 Iterable,您的类可以对传入的元素数量有一定的保证。如果您的类本身是 Collection,这尤其可取。

        就我的两分钱...

        【讨论】:

        • 这不允许相当​​不合理的迭代,但也不允许非收集,完全合理的迭代。
        • 而且,其实一个Collection也可以大于Interger.MAX_VALUE,那么size方法只返回Integer.MAX_VALUE。 Collection 的优势主要是 size() 方法(其他所有东西都可以在 Iterator 和 size 之上实现,如 AbstractCollection 所示),所以使用 Collection 在迭代之前需要大小时 ,而不是当您只想迭代时。
        • @Paŭlo:哇,我不知道Collection.size() 会返回Integer.MAX_VALUE,如果它包含的元素不止这么多!
        • 是的! Javadoc proof!
        【解决方案7】:

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

        【讨论】:

          【解决方案8】:

          请参阅“为什么如此强调迭代器和可迭代对象?”在Google Collection FAQ 为首选迭代器提供了一个不错的论据,尤其是在处理大量数据时。一个可能有帮助的类比是思考只进只读游标和可滚动游标之间的区别。

          【讨论】:

            【解决方案9】:

            Spring Data JPA 的用户会发现Repositories 返回类型为Iterable&lt;T&gt;. 的集合

            在我过去从事的使用Spring 的项目中,我发现在检索后对集合进行操作的需要通常要求在业务层使用Iterable&lt;T&gt; 而不是@987654326 @ 以便从集合中选择一个对象T

            所有的Collection都是Iterable(即扩展Collection接口的接口,所以不是Map!),所以在业务层使用Iterable仅仅是通过其引用Collection的一种情况超级类型,仍然允许使用for-each 进行迭代。

            如果您需要操作集合的内容,一种方便的方法可以让您填充新的Collection,因此您可以将contains()remove() 等与原始集合数据一起使用。

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

            【讨论】:

              猜你喜欢
              • 2010-09-21
              • 2011-10-14
              • 2013-02-25
              • 1970-01-01
              • 1970-01-01
              • 2012-01-21
              • 2010-11-17
              • 1970-01-01
              • 2011-10-01
              相关资源
              最近更新 更多