来自Java 1.6 Collection Framework documentation:
不支持任何修改操作的集合(例如
add
,remove
和clear
)称为 unmodifiable 。 [...]另外保证Collection对象中的任何更改都不可见的集合称为 immutable 。
第二个标准让我感到困惑。鉴于第一个集合是不可修改的,并假设原始集合引用已被丢弃,第二行中引用的更改是什么?它是指集合中保存的元素的变化,即元素的状态?
第二个问题:
对于一个不可变的集合,如何提供额外的guarentees指定?如果集合中的元素状态由一个线程更新,那么状态中的那些更新在持有不可变集合的线程上是不可见的,这对于不可变性是否足够?
对于一个不可变的集合,如何提供额外的guarentees指定?
答案 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返回新的集合。
免责声明:我是
的开发者