Java 不可变集合

来自 Java 1.6 Collection Framework 文档:

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

第二个标准让我有点困惑。假设第一个集合是不可修改的,并且假设原始集合引用已被释放,那么第二行中引用的更改是什么?它是否指的是集合中元素(即元素的状态)的变化?

第二个问题:
For a collection to be immutable, how does one go about providing the additional guarentees specified? If the state of an element in the collection is updated by a thread, is it sufficient for immutability that those updates in the state are not visible on the thread holding the immutable collection?

对于不可变的集合,如何提供指定的附加保证?

194264 次浏览

区别在于,您不能引用允许更改的不可变集合。不可修改的集合是不可修改的 通过那个引用,但是其他一些对象可能指向可以通过它进行更改的相同数据。

例如:。

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);

不可修改的集合通常是其他集合的只读视图(包装器)。您不能添加、移除或清除它们,但是基础集合可以更改。

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

这是引自番石榴的 ImmutableList

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

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

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

c1易变的(即既不是 无法改变也不是 永恒不变)。
c2unmodifiable: 它本身不能改变,但是如果以后我改变 c1,那么 那个的改变将在 c2中可见。

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

Regarding your second question:

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

I believe the point here is that even if a collection is Unmodifiable, that does not ensure that it cannot change. Take for example a collection that evicts elements if they are too old. Unmodifiable just means that the object holding the reference cannot change it, not that it cannot change. A true example of this is Collections.unmodifiableList method. It returns an unmodifiable view of a List. The the List reference that was passed into this method is still modifiable and so the list can be modified by any holder of the reference that was passed. This can result in ConcurrentModificationExceptions and other bad things.

不可变,意味着集合不能被更改。

Second question: An Immutable collection does not mean that the objects contained in the collection will not change, just that collection will not change in the number and composition of objects that it holds. In other words, the collection's list of references will not change. That does not mean that the internals of the object being referenced cannot change.

Pure4J supports what you are after, in two ways.

首先,它提供了一个 @ImmutableValue注释,这样您就可以对一个类进行注释,说明它是不可变的。有一个专家插件,让你检查你的代码 实际上是不可变(使用 final等)。

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

免责声明: 我是这个的开发者

现在 java 9已经有了用于不变列表、集合、映射和映射的工厂方法。

In Java SE 8 and earlier versions, We can use Collections class utility methods like unmodifiableXXX to create Immutable Collection objects.

然而,这些 Collections.undifiableXXX 方法是非常繁琐和冗长的方法。为了克服这些缺点,Oracle 公司在 List、 Set 和 Map 接口中增加了几个实用方法。

Now in java 9 :- List and Set interfaces have “of()” methods to create an empty or no-empty Immutable List or Set objects as shown below:

空列表示例

List immutableList = List.of();

非空列表示例

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

在 Java 9之前,Collections.unmodfiableXXX ()方法用于创建不可修改的集合。这些方法的行为类似于返回原始集合的不可修改视图或只读视图的包装器方法。即不能通过这些包装器方法返回的引用执行添加、删除、替换、清除等修改操作。但是,如果对原始集合有其他引用,并且这些修改将反映在这些方法返回的视图中,则可以修改原始集合。

For example,

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
 

public class Java9ImmutableCollections
{
public static void main(String[] args)
{
List<String> sportList = new ArrayList<String>();
         

sportList.add("Hockey");
sportList.add("Cricket");
sportList.add("Tennis");
         

List<String> unModifiableSportList = Collections.unmodifiableList(sportList);
 

System.out.println(sportList);    //Output : [Hockey, Cricket, Tennis]
         

System.out.println(unModifiableSportList);    //Output : [Hockey, Cricket, Tennis]
         

unModifiableSportList.add("Wrestling");     //It gives run-time error
         

sportList.add("Kabaddi");      //It gives no error and will be reflected in unModifiableSportList
         

System.out.println(sportList);    //Output : [Hockey, Cricket, Tennis, Kabaddi]
         

System.out.println(unModifiableSportList);    //Output : [Hockey, Cricket, Tennis, Kabaddi]
         

}
}

From Java 9, static factory methods are introduced to create immutable collections.

1) Immutable List : List.of()
2) Immutable Set : Set.of()
3) Immutable Map : Map.of() or Map.ofEntries()

不可改变与不可改变:

Java9不可变集合和 Collections.unmodfiableXXX ()包装器方法返回的不可修改集合是不同的。不可修改的集合只是原始集合的只读视图。您可以对原始集合执行修改操作,这些修改将反映在这些方法返回的集合中。但是,Java9静态工厂方法返回的不可变集合是100% 不可变的。一旦它们被创建,您就不能修改它们。

资料来源: https://javaconceptoftheday.com/java-9-immutable-collections/