【问题标题】:Do containsAll() and retainAll() in the Collection interface address cardinality?Collection接口地址基数中的containsAll()和retainAll()?
【发布时间】:2009-05-03 05:05:47
【问题描述】:

在 Java 中,AbstractCollection 类中的 containsAll 和 retainAll 明确声明不尊重基数,因此换句话说,每边有多少个值实例并不重要。由于标准库中的所有 Java 集合都扩展了 AbstractCollection,因此假设它们都以相同的方式工作。

但是,Collection 接口中这些方法的文档并没有说明什么。是应该从 AbstractCollection 推断,还是故意未指定以允许定义不同工作方式的集合?

例如,apache-collections 中的 Bag 明确声明它确实尊重基数,并声称它违反了 Collection 版本的合同(尽管它实际上并非如此)。

那么,这些操作在 Collection 中而不是在 AbstractCollection 中的语义是什么?

编辑:那些想知道我为什么会关心的人,那是因为作为我博士学位的一部分。工作我证明了开发人员并不期望在 Apache 中出现一致性违规,但我试图理解为什么 Collection 接口如此模棱两可。

【问题讨论】:

    标签: java collections


    【解决方案1】:

    containsAll (in Collection) 的 javadocs 说:

    返回:如果此集合为真 包含所有元素 指定集合

    对于retainAll(在集合中):

    只保留 this 中的元素 集合中包含的 指定的集合(可选 手术)。换句话说,删除 从这个集合中,它的所有 不包含在 指定的集合。

    我读到 containsAll 的约定意味着调用 a.containsAll(b) 将返回 true,当且仅当为 b 中的每个元素 bElem 调用 a.contains(bElem) 将返回 true。我还认为它暗示 a.containsAll(someEmptyCollection) 也会返回 true。当您更明确地声明 AbstractCollection 的 javadocs 时:

    此实现迭代 指定的集合,检查每个 迭代器返回的元素 in 转过来看看它是否包含在这个 收藏。如果所有元素都是这样 包含 true 返回,否则 假的。

    我同意 Collection for containsAll 的联系方式应该更加明确,以避免任何混淆的可能性。 (并且阅读 AbstractCollection 的 javadocs 不应该是确认人们对 Collection 的理解所必需的)

    在调用retainAll 之后,我不会对重复元素的数量做出假设。 Collection 中规定的合同(根据我的阅读)并不意味着如何处理任一集合中的重复项。根据我对retainAll in collection 的阅读,a.retainAll(b) 的多个可能结果都是合理的:

    1. 结果包含每个元素中的 1 个,并且在 a 和 b 中都至少有一个副本
    2. result 包含 a 中的每个元素(包括重复项),但不在 b 中的元素除外
    3. 甚至,结果包含介于 1 和 a 中每个元素的 a 中找到的副本数之间的某个位置,除了那些不在 b 中的元素。 我本来期望 #1 或 #2,但会根据合同假设这三个中的任何一个都是合法的。

    AbstractCollection 的 javadocs 确认它使用 #2:

    这个实现迭代这个 集合,检查每个元素 由迭代器依次返回 查看它是否包含在指定的 收藏。如果它不是那么包含, 它已从此集合中删除 迭代器的remove方法

    虽然这不在我阅读原始 Collection 接口合同的范围内,但我不一定会假设 Collection 的行为通常是这样的。

    也许您应该考虑在完成后向 JavaDoc 提交建议的更新。

    至于“为什么 Collection 接口如此模棱两可”——我严重怀疑这是有意为之——可能只是在编写 API 的那部分时没有给予其应有的优先级。

    【讨论】:

      【解决方案2】:

      我不认为 Collection 以这种或其他方式定义它,但它只是成为一种遵循 AbstractCollection 行为的约定,例如google-collections do:参见their Multiset documentation(Multiset 就是他们所说的 Bag)

      【讨论】:

      • 问题是约定可能会导致对界面的误解。例如,Apache 中 Bag 的文档说这是在 Collection 中说明的,即使它在 AbstractCollection 中说明。从实现的典型行为中推断接口契约通常不是一个好主意...
      • 我完全同意你的看法。这是事实上的合同,而不是法律上的合同。所以我认为以不同的方式实现集合是可以的,但要强调 Javadoc 中的差异,就像 Apache Collections 所做的那样。
      猜你喜欢
      • 2023-03-16
      • 2011-04-28
      • 2019-02-03
      • 1970-01-01
      • 2020-02-06
      • 2020-12-04
      • 1970-01-01
      • 2016-10-27
      • 1970-01-01
      相关资源
      最近更新 更多