是否有一种通用的方法来从Collection / List / Set中创建一个不可修改的List / Set / Map ......?

时间:2016-04-20 14:42:04

标签: java collections clone

java util Collections类offers,用于在任何现有列表周围创建“不可修改的”装饰器。但是我们都知道(或者在某些方面努力学习);它实际上只是一个最初传递给该调用的列表中的装饰器。装饰清单无法更改;但如果“原始”清单被修改,它将在封面下发生变化。

现在假设我有一些像

这样的课程
class Whatever {
   private final List<IDontCare> someElements;
   public Whatever(List<IDontCare> incomingElements) {
      someElements = unmodifiableCopyOf(incomingElements);

该类简单想要使用传入数据的真正不可修改的副本。好主意 - 但似乎没有干净/通用的方法来实现该方法unmodifiableCopyOf()

人们可以想到:

  • 使用“clone()”来创建副本......遗憾的是,“可见”clone()仅存在于像ArrayList这样的具体实现上;但如果我只知道“它是实施清单的东西”......那么;我无法克隆(很好地解释here
  • 简单地创建一个“中间容器”;比如新的ArrayList(incomingElements)并且有“装饰”;但是如果incomingElements是一个链表呢?
  • 使用其他库,例如提供"A high-performance, immutable, random-access List implementation"的Guava。但是,Guava不是我的选择(我们几乎只限于我们自己的库和一些Apache公共的东西)。

Tl;博士:这个问题真的没有“通用”解决方案(依赖“标准库”),它给了我一个真正无法修改的集合;基于其他一些收藏?

3 个答案:

答案 0 :(得分:2)

选项#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,则将使用第三个构造函数。

答案 1 :(得分:1)

  

是否有通用的方法从Collection / List / Set中创建一个不可修改的List / Set / Map?

是的!使用Collections.unmodifiable... s。

Set<String> stuff = Collections.<String>unmodifiableSet(oldSet);
  

装饰清单无法更改;但如果&#34;原创&#34;列表已修改。

如果你不想要,那么错误在于处理原始集合而不是构建新集合。你应该在构建时复制它。

    Set<String> uset = Collections.<String>unmodifiableSet(new HashSet<>(oldSet));

答案 2 :(得分:1)

tl; dr

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 Javadoc:

以迭代顺序返回包含给定Collection元素的unmodifiable List。给定的Collection不能为null,并且不得包含任何null元素。如果随后修改了给定的Collection,则返回的List将不会反映出这种修改。

Set.copyOf

与之类似,Set接口提供了一种Set.copyOf方法来生成一组单独的新对象,这些对象与原始对象中的对象相同。

Map.copyOf

继续遵循这个主题,Map界面提供了一种Map.copyOf方法来生成一个单独的新映射,其中包含与原始键相同的键和值。