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

时间:2011-05-13 00:59:12

标签: java collections

我很好奇从可变类返回一组对象时被认为是更好的做法:

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 个答案:

答案 0 :(得分:6)

我认为没有一个简单的“最佳实践”答案。这实际上取决于您愿意花费多少机器资源来防止违反类数据抽象边界。这取决于你实际上试图减轻的风险;例如是简单(非并发)错误,并发错误还是信息泄漏。

选项包括:

  • 什么都不做;即按原样退回收藏。
  • 返回包装在不可变包装类中的集合。
  • 返回该集合的浅表副本。
  • 返回该集合的深层副本。

除了复制的直接成本之外,其他与性能相关的因素还包括内存使用和垃圾生成以及对并发性的影响。例如,如果多个线程正在更新集合和/或“获取”它,那么制作集合的副本通常涉及锁定它......这可能会使操作成为并发瓶颈。

总之,您需要在不采取预防措施的情况下平衡成本/性能影响与潜在或实际风险和成本。

答案 1 :(得分:1)

我喜欢使用后者,但使用.clone()方法。

答案 2 :(得分:0)

如果您担心暴露变化;并且您的对象实现了Cloneable,然后您可以将对象列表的克隆深层副本返回给调用者。

答案 3 :(得分: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 not。