是否有一种通用方法可以从 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().

可以想到:

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.copyOfJava文档:

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 方法生成一个单独的新映射,其中包含原始中保存的相同键和值。