我需要确保我创建的某个Set<String>
不会在代码中的其他位置修改。当然,我最终使用了番石榴ImmutableSet。
这个不可变集非常大(大约59K字符串),每次调用特定方法时我都必须执行Set#contains
检查。所以我想知道是否有任何方法可以指定大集合中的查找。 Guava的文档说:
具有可靠性,用户指定的高性能,不可变集 迭代顺序。不允许使用null元素。
如果通过调用user-specified iteration
创建了不可变集合,ImmutableSet#copyOf(aHashSet)
意味着什么?如果我使用contains(String)
代替ImmutableSet#contains
,HashSet#contains
的效果会受到不利影响吗?更确切地说,我的问题如下:
使用相当好的哈希函数并且没有太多元素进入同一个存储桶,人们会期望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)操作。
答案 0 :(得分:3)
我在the documentation中看到的唯一确认如下:
此类的工厂方法创建基于哈希的实例,...
换句话说,您可以期望查找使用类似于HashSet
的散列机制(因此具有性能特征)。文档是故意模糊的,因此可以进行各种改进(例如,对某些特殊情况使用特殊实现,如单例或空集)。
迭代顺序取决于创建方法。在copyOf
的情况下,它将是您传入的Iterable
的迭代顺序(当然,在复制时)。这有很好的记录:
按顺序返回包含给定元素的不可变集合。
至于它是否遵循set的contains方法,没有。由于ImmutableSet
制作副本(与Collections.unmodifiableSet()
不同),因此显然无法按照原始集合进行任何操作。
答案 1 :(得分:2)
马克彼得斯回答的一小部分内容。
使用RegularImmutableSet
通过将元素存储两次(一次排序,一次哈希)来保存顺序。这仍然比委托给HashSet
的原始HashMap
便宜,SingletonImmutableSet
为存储的每个元素创建一个条目。
有优化的实施EmptyImmutableSet
和O(1)
。还有许多其他的东西,当你从一个不可变的集合或地图开始时使用。
如果您想了解更多信息,请使用source(但仅取决于文档)。
您链接的性能讨论仅处理哈希冲突。通常,性能为RegularImmutableSet
,只是在哈希函数非常糟糕的情况下,它会退化。这适用于所有散列数据结构,但效果不同。 HashSet
具有更好的数据位置,{{1}}使用链接,可以更好地处理冲突。
曾经有一个problem,其中某种冲突会导致过多的冲突,但很久以前就已经修复了。现在,偶然遇到类似事情是不可能的。