Java不可变集合

时间:2011-10-10 13:12:42

标签: java collections immutability

来自Java 1.6 Collection Framework documentation

  

不支持任何修改操作的集合(例如addremoveclear)称为 unmodifiable 。 [...]另外保证Collection对象中的任何更改都不可见的集合称为 immutable

第二个标准让我感到困惑。鉴于第一个集合是不可修改的,并假设原始集合引用已被丢弃,第二行中引用的更改是什么?它是指集合中保存的元素的变化,即元素的状态?

第二个问题:
对于一个不可变的集合,如何提供额外的guarentees指定?如果集合中的元素状态由一个线程更新,那么状态中的那些更新在持有不可变集合的线程上是不可见的,这对于不可变性是否足够?

对于一个不可变的集合,如何提供额外的guarentees指定?

6 个答案:

答案 0 :(得分:146)

不可修改的集合通常是其他集合的只读视图(包装器)。您无法添加,删除或清除它们,但基础集合可能会发生变化。

不可变的集合根本无法更改 - 它们不会包装另一个集合 - 它们有自己的元素。

以下是番石榴ImmutableList

的引用
  

Collections.unmodifiableList(java.util.List<? extends T>)不同,ImmutableList是一个可以更改的单独集合的视图,{{1}}的实例包含自己的私有数据,永远不会更改。

因此,基本上,为了从可变的集合中获取不可变集合,您必须将其元素复制到新集合,并禁止所有操作。

答案 1 :(得分:84)

不同之处在于您不能引用允许更改的不可变集合。不可修改的集合不可修改通过该引用,但某些其他对象可能指向可通过其更改的相同数据。

e.g。

List<String> strings = new ArrayList<String>();
List<String> unmodifiable = Collections.unmodifiableList(strings);
unmodifiable.add("New string"); // will fail at runtime
strings.add("Aha!"); // will succeed
System.out.println(unmodifiable);

答案 2 :(得分:19)

Collection<String> c1 = new ArrayList<String>();
c1.add("foo");
Collection<String> c2 = Collections.unmodifiableList(c1);

c1 mutable (即不可修改的 c2 无法修改:它无法自行更改,但如果稍后我更改了c1,那么 更改将在{{ 1}}。

这是因为c2只是c2的包装,而不是真正的独立副本。 Guava提供ImmutableList interface和一些实现。这些工作通过实际创建输入的副本(除非输入本身是不可变的集合)。

关于你的第二个问题:

集合的可变性/不变性取决于其中包含的对象的可变性/不变性。修改集合中包含的对象计为此描述的“集合修改”。当然,如果你需要一个不可变的集合,通常也希望它包含不可变的对象。

答案 3 :(得分:13)

现在 java 9 具有不可变列表,设置,地图和Map.Entry的工厂方法。

在Java SE 8及更早版本中,我们可以使用Collections类实用程序方法(如unmodifiableXXX)来创建Immutable Collection对象。

然而,这些Collections.unmodifiableXXX方法是非常乏味和冗长的方法。为了克服这些缺点,Oracle公司已经为List,Set和Map接口添加了几种实用方法。

现在在java 9中: - List和Set接口有“of()”方法来创建一个空的或不空的Immutable List或Set对象,如下所示:

清单列表示例

List immutableList = List.of();

非空列表示例

List immutableList = List.of("one","two","three");

答案 4 :(得分:6)

我认为这里的观点是,即使集合是不可修改的,也不能确保它不能改变。例如,如果元素太旧,则会逐出元素。不可修改只是意味着持有引用的对象不能改变它,而不能改变它。一个真实的例子是Collections.unmodifiableList方法。它返回List的不可修改的视图。传递给此方法的List引用仍然是可修改的,因此可以由传递的引用的任何持有者修改列表。这可能导致ConcurrentModificationExceptions和其他不好的事情。

永恒,意味着不能改变收藏。

第二个问题:不可变集合并不意味着集合中包含的对象不会改变,只是集合不会改变它所拥有的对象的数量和组成。换句话说,集合的引用列表不会改变。这并不意味着被引用对象的内部结构不能改变。

答案 5 :(得分:0)

Pure4J以两种方式支持你所追求的目标。

首先,它提供了一个@ImmutableValue注释,以便您可以注释一个类来说明它是不可变的。有一个maven插件可以让你检查你的代码实际上是不可变的(使用final等)。

其次,它提供了来自Clojure的持久集合(带有添加的泛型),并确保添加到集合中的元素是不可变的。这些表现显然相当不错。集合都是不可变的,但实现了java集合接口(和泛型)以供检查。 Mutation返回新的集合。

免责声明:我是

的开发者