关于不可变集合,我有一个普遍的问题。我将使用Java作为参考实验室,因为我知道它最好。
首先,是否有确保不变性的一般方法?我的意思是,是否应该复制整个集合,进行更改然后返回新对象?还有更复杂,更通用的方法吗?
更进一步,那些“明显的”(对我来说)可变的集合,比如树?通常它们被实现为具有N个子节点的节点。在这种情况下,您如何保证不变性?以递归方式克隆和复制所有引用?
根据上述内容,我想知道这些集合的最佳方法是什么:
非常感谢您的回复。
答案 0 :(得分:6)
令人高兴的是,大部分内容已经为您完成,请查看google guava,其中包含ImmutableCollection,ImmutableList,ImmutableSet,ImmutableMap等。
通过阻止这些类的子类(通过使它们成为最终类,或使它们的构造函数成为私有)来确保不变性。
当你从一个可变集合中创建一个不可变集合时,会复制可变集合中的数据,然后不允许所有变异操作 - 它们将抛出异常(例如UnsupportedOperationException
)。
出于性能原因,番石榴图书馆将尽力不复制数据,如果他们不需要的话。例如,如果您已经拥有ImmutableMap
,并使用ImmutableMap.copyOf(theOtherImmutableMap)
创建一个新的,则不会复制任何数据,因为我们已经知道其他地图是不可变的,所以可以拥有两个对同一数据的引用。
答案 1 :(得分:2)
就Java而言,Collections实用程序类是你的朋友。而不是手动执行这些操作,我建议通过API给出。特别要看一下不可变和不可修改的方法。
例如,就不可变而言:
<T> List<T>
emptyList()
Returns the empty list (immutable).
static
<K,V> Map<K,V>
emptyMap()
Returns the empty map (immutable).
static
<T> Set<T>
emptySet()
Returns the empty set (immutable).
对于不可修改的,你有:
static
<T> Collection<T>
unmodifiableCollection(Collection<? extends T> c)
Returns an unmodifiable view of the specified collection.
static
<T> List<T>
unmodifiableList(List<? extends T> list)
Returns an unmodifiable view of the specified list.
static
<K,V> Map<K,V>
unmodifiableMap(Map<? extends K,? extends V> m)
Returns an unmodifiable view of the specified map.
static
<T> Set<T>
unmodifiableSet(Set<? extends T> s)
Returns an unmodifiable view of the specified set.
static
<K,V> SortedMap<K,V>
unmodifiableSortedMap(SortedMap<K,? extends V> m)
Returns an unmodifiable view of the specified sorted map.
static
<T> SortedSet<T>
unmodifiableSortedSet(SortedSet<T> s)
还有其他一些策略你可以在下面实现,但我会从那里开始。
答案 2 :(得分:0)
我假设您的目的是了解不可变集合如何在函数式语言框架内工作(如haskell等)。这个想法是所有集合都是不可变的和最终的,从而避免了所有关于可变性,同步等的多线程问题,但仍允许你添加,删除和修改,就好像它们是可变的一样
我见过的最好的例子是Clojure的源代码。它是一种类似于lisp的语言,因此将不可变集合作为核心功能处理。我强烈建议查看如何在clojure中实现集合,因为它们必然会回答您的许多问题。可能有些事情太复杂了(我仍然很难理解 尝试 )。见here祝你好运
答案 3 :(得分:0)
Clojure包含这样的不可变(或持久)collections。
它提供了你所追求的所有集合,并支持通过构造进行变异:简单地说,添加或删除新元素会返回一个新的集合,通常 重用旧的大部分通过巧妙使用Trie类型的数据结构进行收集。
就他们自己来说,这些不适合直接使用Java - 它们被设计用于Clojure。
Pure4j试图将这些(以及Clojure提倡的基于不可变/值的样式)移植到Java语言中。这可能是你追求的目标。
免责声明:我是Pure4J的开发者