Collections.unmodifiableSet()和Guava的ImmutableSet有什么区别?

时间:2011-04-10 11:07:22

标签: java immutability guava

ImmutableSet的JavaDoc说:

  

Collections.unmodifiableSet不同,ImmutableSet是一个可以更改的单独集合的视图,此类的实例包含其自己的私有数据,并且永远不会更改。这个类很方便公共静态最终集(“常量集”),也可以让你轻松制作一个由调用者提供给你的类的集合的“防御性副本”。

但是Collections.unmodifiableSet()仍然存储元素的引用,我无法找出与StringBuffer s=new StringBuffer("a"); ImmutableSet<StringBuffer> set= ImmutableSet.of(s); s.append("b");//s is "ab", s is still changed here! 的区别。样品:

{{1}}

有人可以解释一下吗?

4 个答案:

答案 0 :(得分:78)

考虑一下:

Set<String> x = new HashSet<String>();
x.add("foo");

ImmutableSet<String> guava = ImmutableSet.copyOf(x);
Set<String> builtIn = Collections.unmodifiableSet(x);

x.add("bar");
System.out.println(guava.size()); // Prints 1
System.out.println(builtIn.size()); // Prints 2

换句话说,ImmutableSet是不可变的,尽管它可能通过可能改变而构建的集合 - 因为它创建了一个副本。 Collections.unmodifiableSet阻止返回的集合直接更改,但它仍然是可能更改的后备集的视图。

请注意,如果您开始通过任何设置更改引用对象的内容,则无论如何都会关闭所有投注。不要那样做。实际上,首先使用可变元素类型创建集合并不是一个好主意。 (使用可变密钥类型进行Ditto映射。)

答案 1 :(得分:15)

除了Jon提到的行为差异之外,ImmutableSetSet创建的Collections.unmodifiableSet之间的重要区别在于ImmutableSet类型。您可以传递一个,并且通过在整个代码中使用ImmutableSet而不是Set来清楚地表明该集是不可变的。对于Collections.unmodifiableSet,返回的类型只是Set ...因此,只有在创建它时,该集合才可以无法修改,除非您在传递Set所说的任何地方添加Javadoc “这套不可修改”。

答案 2 :(得分:10)

Kevin Bourrillion(Guava首席开发人员)在this presentation中比较了不可变/不可修改的集合。虽然演示文稿已有两年历史,并专注于“Google Collections”(现在是Guava的子部分),但这是一个非常有趣的演示文稿。 API可能已经发生变化(Google Collections API当时处于测试阶段),但Google Collections / Guava背后的概念仍然有效。

您可能也对this other SO question感兴趣( Google的ImmutableList和Collections.unmodifiableList()之间有什么区别。)

答案 3 :(得分:3)

其他答案中未说明的两者之间的差异是ImmutableSet不允许null值,如Javadoc

中所述
  

具有可靠的,用户指定的迭代顺序的高性能,不可变集合。不允许使用null元素。

(同样的限制适用于所有Guava不可变集合中的值。)

例如:

ImmutableSet.of(null);
ImmutableSet.builder().add("Hi").add(null); // Fails in the Builder.
ImmutableSet.copyOf(Arrays.asList("Hi", null));

所有这些都在运行时失败。相反:

Collections.unmodifiableSet(new HashSet<>(Arrays.asList("Hi", null)));

这很好。