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#contains
,contains(String)
的性能会受到不利影响吗?更准确地说,我的问题如下:
有了一个不错的散列函数并且没有太多元素进入同一个桶,人们会期望 HashSet#contains
是 O(1)。使用 copyOf
创建的 ImmutableSet 会遵守这个吗?
我怀疑情况可能并非如此,原因有二:
Guava forum discussion on precisely this question(虽然似乎没有提供确凿的答案)。
我不清楚 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
便宜,后者为每个存储的元素创建一个条目。
有优化的实现 SingletonImmutableSet
和 EmptyImmutableSet
。还有许多其他在您从不可变集合或地图开始时会用到的东西。
如果您想了解更多信息,请使用 source(但仅取决于文档)。
您链接的性能讨论仅涉及哈希冲突。通常情况下,性能是 O(1)
,只是在哈希函数非常糟糕的情况下,它会退化。这适用于所有散列数据结构,但效果不同。 RegularImmutableSet
具有更好的数据局部性,HashSet
使用链接并且可以更好地处理冲突。
曾经有一个problem,是因为某种冲突导致碰撞次数过多,不过早就修复了。现在,不可能 运行 偶然变成类似的东西。
我需要确保我创建的某个 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#contains
,contains(String)
的性能会受到不利影响吗?更准确地说,我的问题如下:
有了一个不错的散列函数并且没有太多元素进入同一个桶,人们会期望 HashSet#contains
是 O(1)。使用 copyOf
创建的 ImmutableSet 会遵守这个吗?
我怀疑情况可能并非如此,原因有二:
Guava forum discussion on precisely this question(虽然似乎没有提供确凿的答案)。
我不清楚
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
便宜,后者为每个存储的元素创建一个条目。
有优化的实现 SingletonImmutableSet
和 EmptyImmutableSet
。还有许多其他在您从不可变集合或地图开始时会用到的东西。
如果您想了解更多信息,请使用 source(但仅取决于文档)。
您链接的性能讨论仅涉及哈希冲突。通常情况下,性能是 O(1)
,只是在哈希函数非常糟糕的情况下,它会退化。这适用于所有散列数据结构,但效果不同。 RegularImmutableSet
具有更好的数据局部性,HashSet
使用链接并且可以更好地处理冲突。
曾经有一个problem,是因为某种冲突导致碰撞次数过多,不过早就修复了。现在,不可能 运行 偶然变成类似的东西。