Java不可变集合

Bha*_*kar 108 java collections immutability

Java 1.6 Collection Framework文档:

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

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

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

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

Boz*_*zho 148

不可修改的集合通常是其他集合的只读视图(包装器).您无法添加,删除或清除它们,但底层集合可能会更改.

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

这是番石榴的引用 ImmutableList

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

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

  • 如果包装在另一个不可修改集合中的集合没有任何其他对其的引用,那么不可修改集合的行为与不可变集合完全相同吗? (3认同)

Sim*_*son 84

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

例如

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);
Run Code Online (Sandbox Code Playgroud)


Joa*_*uer 19

Collection<String> c1 = new ArrayList<String>();
c1.add("foo");
Collection<String> c2 = Collections.unmodifiableList(c1);
Run Code Online (Sandbox Code Playgroud)

c1可变的(即,既不不可修改的,也没有不可变).
c2不可修改的:它不能自行更改,但如果稍后我更改,c1那么更改将在中显示c2.

这是因为c2它只是一个包装器c1而不是真正的独立副本.Guava提供了ImmutableList接口和一些实现.这些工作通过实际创建输入的副本(除非输入是自己的不可变集合).

关于你的第二个问题:

集合的可变性/不变性依赖于其中包含的对象的可变性/不变性.修改集合中包含的对象不会视为此描述的"集合的修改".当然,如果您需要一个不可变集合,通常也希望它包含不可变对象.

  • @John:不,不是.至少不符合OP引用的定义. (2认同)

Vij*_*pta 15

现在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();
Run Code Online (Sandbox Code Playgroud)

非空列表示例

List immutableList = List.of("one","two","three");
Run Code Online (Sandbox Code Playgroud)

  • 在 Java 10 中添加了 `List.copyOf` 和 `Set.copyOf`,允许创建列表/集合的不可修改副本,或者如果给定集合已经不可修改则返回给定集合,请参阅 [JDK-8191517](https: //bugs.openjdk.java.net/browse/JDK-8191517) (3认同)

Joh*_*n B 6

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

不可变,意味着收集不会被改变.

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