在Java中返回内部集合的最佳实践是什么?

12

我很好奇在从可变类返回对象集合时,什么被认为是更好的做法:

public class Someclass {

  public List<String> strings;  

  public add(String in){ strings.add(in); }
  public remove(String in) { strings.remove(in); }   

  //THIS
  public List<String> getStrings(){
    return Collections.unmodifiableList(strings);
  }

  //OR THIS
  public List<String> getStrings(){
    return new ArrayList(strings);
  }
}

我一直认为将内部集合包装在一个不可修改的Unmodifiable中是最好的方法,因为我认为没有理由要额外生成一个副本。然而,我意识到在内部对列表进行的任何更改都将暴露给客户端,这让我觉得很糟糕。

4个回答

8
我认为对于这个问题并没有简单的“最佳实践”答案。这主要取决于您愿意花费多少机器资源来防止类数据抽象边界的违规,并且取决于您实际试图缓解的风险,例如简单(非并发)错误、并发错误或信息泄露。
选项包括:
- 什么也不做,即原样返回集合。 - 返回包装在不可变的包装类中的集合。 - 返回集合的浅表副本。 - 返回集合的深层副本。
除了直接复制的成本外,其他与性能相关的因素还包括内存使用和垃圾生成以及对并发的影响。例如,如果多个线程正在更新集合和/或“获取”它,则通常需要锁定集合才能进行复制...这可能会使操作成为并发瓶颈。
总之,您需要平衡成本/性能影响与不采取预防措施的潜在或实际风险和成本。

2

我喜欢使用.clone()方法来实现后者。


后一种方法,使用新的ArrayList或使用.clone(),是减少并发问题的正确方法。在多线程环境中,Collections.unmodifiableList()会增加可能的并发问题。 - Julius Musseau

0
如果您担心暴露更改,并且您的对象实现了Cloneable接口,那么您可以返回一个克隆的深层副本对象列表给调用者。

0
'

使用'new ArrayList(strings)'比'Collections.unmodifiableList(strings)'更安全。

因为Collections.unmodifiableList只是将源列表转发。

示例:

'
List<String> list1 = someclass.getStrings(); //Use Collections.unmodifiableList(strings) implementation
List<String> list2 = someclass.getStrings(); //Use new ArrayList(strings) implementation

someclass.add("foo");

现在,你会看到list1被添加了!但是list2没有。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接