是否有一种通用方法可以从 Collection/List/Set... 创建不可修改的 List/Set/Map?
Is there a generic way to create an un-modifiable List/Set/Map from Collection/List/Set... ?
java util Collections class offers 围绕任何现有列表创建一个 "unmodifiable" 装饰器。但众所周知(或在某些时候学到了困难的方法);它实际上只是最初传递给该调用的列表周围的装饰器。修饰列表不能改变;但如果 "original" 列表被修改,它会在幕后发生变化。
现在假设我有一些class喜欢
class Whatever {
private final List<IDontCare> someElements;
public Whatever(List<IDontCare> incomingElements) {
someElements = unmodifiableCopyOf(incomingElements);
那个 class 简单想要使用传入数据的真正不可修改的副本。好主意 - 但似乎没有 clean/generic 方法来实现该方法 unmodifiableCopyOf()
.
可以想到:
- 使用"clone()"创建一个副本...不幸的是,"visible" clone() 只存在于像ArrayList 这样的具体实现上;但如果我只知道 "it is something implementing List" ... 好吧;我无法克隆(很好地解释 here)
- 只需创建一个"intermediate container";像 new ArrayList(incomingElements) 一样 "decorated";但是如果 incomingElements 是一个链表呢?
- 使用其他一些库,例如提供 "A high-performance, immutable, random-access List implementation" 的 Guava。但是,Guava 在我这里不是一个选择(我们几乎只能使用我们自己的库和一些 Apache 通用的东西)。
Tl;dr:这个问题真的没有 "generic" 解决方案(依赖于 "standard libraries")是什么给我一个真正不可修改的集合?基于其他一些集合?
Is there a generic way to create an un-modifiable List/Set/Map from Collection/List/Set… ?
是的!使用 Collections.unmodifiable...
s.
Set<String> stuff = Collections.<String>unmodifiableSet(oldSet);
The decorated list can't be changed; but it will change under the covers if the "original" list is modified.
如果您不想那样做,那么问题出在对原始集合的处理上,而不是新集合的构造上。您应该在构建时复制一份。
Set<String> uset = Collections.<String>unmodifiableSet(new HashSet<>(oldSet));
选项#1
public Whatever(List srcList) {
Constructor<? extends List> c = srcList.getClass().getConstructor(Collection.class);
someElements = unmodifiableList(c.newInstance(srcList));
省略了try-catch。这适用于 java.util
中的列表,但不能保证自定义列表。
选项 #2
public Whatever(ArrayList srcList) {
someElements = unmodifiableList(new ArrayList(srcList));
public Whatever(LinkedList srcList) {
someElements = unmodifiableList(new LinkedList(srcList));
public Whatever(List srcList) {
someElements = unmodifiableList(new ArrayList(srcList)); // ok, no info
不要被这个解决方案欺骗,如果传递给构造函数的列表引用是 List
类型,将使用第三个构造函数。
tl;博士
Java 10 完全添加了您想要的内容:copyOf
方法,您可以在其中传递列表、集合或映射,并取回新的副本,而不是查看由 Collections.unmodifiable…
。
List.copyOf
Set.copyOf
Map.copyOf
List.copyOf
在 Java 10 及更高版本中,将可修改的 List
传递给 List.copyOf
。
List< Person > peopleUnmod = List.copyOf( people ) ;
生成的列表是真正的副本,与原始列表分开,而不是像 Collections.unmodifiableList
那样的原始视图。
引用List.copyOf
Java文档:
Returns an unmodifiable List
containing the elements of the given Collection, in its iteration order. The given Collection must not be null, and it must not contain any null elements. If the given Collection is subsequently modified, the returned List will not reflect such modifications.
Set.copyOf
同样,Set
接口提供了一种 Set.copyOf
方法来生成一组单独的新对象,这些对象与原始对象相同。
Map.copyOf
继续这个主题,Map
interface offers a Map.copyOf
方法生成一个单独的新映射,其中包含原始中保存的相同键和值。
java util Collections class offers 围绕任何现有列表创建一个 "unmodifiable" 装饰器。但众所周知(或在某些时候学到了困难的方法);它实际上只是最初传递给该调用的列表周围的装饰器。修饰列表不能改变;但如果 "original" 列表被修改,它会在幕后发生变化。
现在假设我有一些class喜欢
class Whatever {
private final List<IDontCare> someElements;
public Whatever(List<IDontCare> incomingElements) {
someElements = unmodifiableCopyOf(incomingElements);
那个 class 简单想要使用传入数据的真正不可修改的副本。好主意 - 但似乎没有 clean/generic 方法来实现该方法 unmodifiableCopyOf()
.
可以想到:
- 使用"clone()"创建一个副本...不幸的是,"visible" clone() 只存在于像ArrayList 这样的具体实现上;但如果我只知道 "it is something implementing List" ... 好吧;我无法克隆(很好地解释 here)
- 只需创建一个"intermediate container";像 new ArrayList(incomingElements) 一样 "decorated";但是如果 incomingElements 是一个链表呢?
- 使用其他一些库,例如提供 "A high-performance, immutable, random-access List implementation" 的 Guava。但是,Guava 在我这里不是一个选择(我们几乎只能使用我们自己的库和一些 Apache 通用的东西)。
Tl;dr:这个问题真的没有 "generic" 解决方案(依赖于 "standard libraries")是什么给我一个真正不可修改的集合?基于其他一些集合?
Is there a generic way to create an un-modifiable List/Set/Map from Collection/List/Set… ?
是的!使用 Collections.unmodifiable...
s.
Set<String> stuff = Collections.<String>unmodifiableSet(oldSet);
The decorated list can't be changed; but it will change under the covers if the "original" list is modified.
如果您不想那样做,那么问题出在对原始集合的处理上,而不是新集合的构造上。您应该在构建时复制一份。
Set<String> uset = Collections.<String>unmodifiableSet(new HashSet<>(oldSet));
选项#1
public Whatever(List srcList) {
Constructor<? extends List> c = srcList.getClass().getConstructor(Collection.class);
someElements = unmodifiableList(c.newInstance(srcList));
省略了try-catch。这适用于 java.util
中的列表,但不能保证自定义列表。
选项 #2
public Whatever(ArrayList srcList) {
someElements = unmodifiableList(new ArrayList(srcList));
public Whatever(LinkedList srcList) {
someElements = unmodifiableList(new LinkedList(srcList));
public Whatever(List srcList) {
someElements = unmodifiableList(new ArrayList(srcList)); // ok, no info
不要被这个解决方案欺骗,如果传递给构造函数的列表引用是 List
类型,将使用第三个构造函数。
tl;博士
Java 10 完全添加了您想要的内容:copyOf
方法,您可以在其中传递列表、集合或映射,并取回新的副本,而不是查看由 Collections.unmodifiable…
。
List.copyOf
Set.copyOf
Map.copyOf
List.copyOf
在 Java 10 及更高版本中,将可修改的 List
传递给 List.copyOf
。
List< Person > peopleUnmod = List.copyOf( people ) ;
生成的列表是真正的副本,与原始列表分开,而不是像 Collections.unmodifiableList
那样的原始视图。
引用List.copyOf
Java文档:
Returns an unmodifiable
List
containing the elements of the given Collection, in its iteration order. The given Collection must not be null, and it must not contain any null elements. If the given Collection is subsequently modified, the returned List will not reflect such modifications.
Set.copyOf
同样,Set
接口提供了一种 Set.copyOf
方法来生成一组单独的新对象,这些对象与原始对象相同。
Map.copyOf
继续这个主题,Map
interface offers a Map.copyOf
方法生成一个单独的新映射,其中包含原始中保存的相同键和值。