Guava 的 ImmutableSet 成员方法是否模仿 java.util.HashSet#contains?

Does Guava's ImmutableSet membership method mimic java.util.HashSet#contains?

我需要确保我创建的某个 Set<String> 没有在代码的其他地方被修改。当然,我最终使用了 Guava 的 ImmutableSet

这个不可变集非常大(大约 59K 字符串),每次调用特定方法时我都必须执行 Set#contains 检查。所以我想知道是否有任何方法可以指定大集合中的查找。番石榴的文档说:

A high-performance, immutable Set with reliable, user-specified iteration order. Does not permit null elements.

如果通过调用 ImmutableSet#copyOf(aHashSet) 创建不可变集,user-specified iteration 意味着什么?如果我使用 ImmutableSet#contains 而不是 HashSet#containscontains(String) 的性能会受到不利影响吗?更准确地说,我的问题如下:

有了一个不错的散列函数并且没有太多元素进入同一个桶,人们会期望 HashSet#contains 是 O(1)。使用 copyOf 创建的 ImmutableSet 会遵守这个吗?

我怀疑情况可能并非如此,原因有二:

  1. Guava forum discussion on precisely this question(虽然似乎没有提供确凿的答案)。

  2. 我不清楚 ImmutableSet#contains 是遵循 java.util.Set#contains(即在我的例子中 HashSet 中的实现)还是 com.google.common.collect.ImmutableCollection#contains .如果是后者,那么ImmutableSet#contains就是一个O(n)的操作。

我在 the documentation 中看到的唯一确认如下:

this class's factory methods create hash-based instances, ...

换句话说,您可以期望查找使用类似于 HashSet 的散列机制(因此具有性能特征)。文档故意含糊不清,以便可以进行各种改进(例如,对某些特殊情况使用特殊实现,如单例或空集)。

迭代顺序将取决于创建方法。在 copyOf 的情况下,它将是您传入的 Iterable 的迭代顺序(当然是在进行复制时)。这是有据可查的:

Returns an immutable set containing the given elements, in order.

至于是否服从set的contains方法,没有。因为 ImmutableSet 制作了一个 copy(不像 Collections.unmodifiableSet()),它显然不能遵从原始集进行任何操作。

只是对 Mark Peters 回答的一个小补充。

使用 RegularImmutableSet 时,通过将元素存储两次(一次排序,一次散列)来保留顺序。这仍然比原始 HashSet 委托给 HashMap 的原始 HashSet 便宜,后者为每个存储的元素创建一个条目。

有优化的实现 SingletonImmutableSetEmptyImmutableSet。还有许多其他在您从不可变集合或地图开始时会用到的东西。

如果您想了解更多信息,请使用 source(但仅取决于文档)。

您链接的性能讨论仅涉及哈希冲突。通常情况下,性能是 O(1),只是在哈希函数非常糟糕的情况下,它会退化。这适用于所有散列数据结构,但效果不同。 RegularImmutableSet 具有更好的数据局部性,HashSet 使用链接并且可以更好地处理冲突。

曾经有一个problem,是因为某种冲突导致碰撞次数过多,不过早就修复了。现在,不可能 运行 偶然变成类似的东西。