Java不可变集合

从Java 1.6 Collection Framework文档 :

不支持任何修改操作(如addremoveclear )的集合被称为不可修改 。 […]另外保证集合对象永远不可见的集合被称为不可变的集合。

第二个标准混淆了我一点。 鉴于第一个集合是不可修改的,并且假设原始集合参考已被废弃,第二行中提到的变化是什么? 它是指在集合中所包含的元素的变化,即元素的状态?

第二个问题:
对于一个集合是不可改变的,一个人怎么去提供额外的保证人? 如果集合中元素的状态由线程更新,那么为了不可变性就足够了:状态中的那些更新在持有不可变集合的线程中不可见?

编辑:(突出第二个问题的重点):

对于一个集合是不可改变的,一个人怎么去提供额外的保证人?

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

不可变的集合根本无法改变 – 它们不包含另一个集合 – 它们有自己的元素。

这里有一个番石榴的ImmutableList的引用

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

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

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

例如

 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); 
 Collection<String> c1 = new ArrayList<String>(); c1.add("foo"); Collection<String> c2 = Collections.unmodifiableList(c1); 

c1可变的 (即既不可修改不可 修改 )。
c2不可修改的 :它不能被改变,但是如果以后改变了c1那么改变将在c2可见。

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

关于你的第二个问题:

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

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

不可改变,意味着collections品绝不能改变。

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

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

在Java SE 8和更早的版本中,我们可以使用不可修改的XXX等Collections类实用工具来创buildImmutable Collection对象。

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

现在在Java 9中: –列表和设置接口有“()”方法来创build一个空的或不空的不可变列表或设置对象,如下所示:

空列表示例

 List immutableList = List.of(); 

非空列表示例

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

Pure4J支持两种方式。

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

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

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