Java 不可变集合

IT小君   2021-10-08T04:52:42

来自Java 1.6 Collection Framework 文档

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

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

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

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

评论(7)
IT小君

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

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

这是番石榴的引述 ImmutableList

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

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

2021-10-08T04:52:43   回复
IT小君

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

例如

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);
2021-10-08T04:52:43   回复
IT小君
Collection<String> c1 = new ArrayList<String>();
c1.add("foo");
Collection<String> c2 = Collections.unmodifiableList(c1);

c1可变的(即既不不可修改也不是不可变的)。
c2不可修改的:它本身无法更改,但如果稍后我更改,c1那么更改将在c2.

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

关于你的第二个问题:

集合的可变性/不变性依赖于其中包含的对象的可变性/不变性。修改包含在集合中的对象并不能算作一个这个描述“收集的修改”。当然,如果你需要一个不可变的集合,你通常也希望它包含不可变的对象。

2021-10-08T04:52:43   回复
IT小君

现在java 9有不可变 List、Set、Map 和 Map.Entry 的工厂方法。

在 Java SE 8 及更早版本中,我们可以使用像 unmodifiableXXX 这样的 Collections 类实用方法来创建不可变的 Collection 对象。

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

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

空列表示例

List immutableList = List.of();

非空列表示例

List immutableList = List.of("one","two","three");
2021-10-08T04:52:43   回复
IT小君

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

不可变的,意味着不能以任何方式更改集合。

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

2021-10-08T04:52:43   回复
IT小君

Pure4J以两种方式支持您的需求。

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

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

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

2021-10-08T04:52:44   回复
IT小君

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

例如,

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]
         
    }
}

从 Java 9 开始,引入了静态工厂方法来创建不可变集合。

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

不可变与不可修改:

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

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

2021-10-08T04:52:44   回复