创建集合的副本

时间:2015-10-14 14:02:22

标签: java list collections copy

我正在阅读J. Bloch的有效Java,现在我正在关于避免返回null但返回空集合的部分。这是以下部分的代码示例:

// The right way to return a copy of a collection
public List<Cheese> getCheeseList() {
  if (cheesesInStock.isEmpty())
    return Collections.emptyList(); // Always returns same list
  else
    return new ArrayList<Cheese>(cheesesInStock);
}

如果cheesesInStock返回cheesesInStock.isEmpty(),我真的无法理解有什么问题。为什么返回预定义的Collections.emptyList()会更好。如果我们返回cheesesInStock,我们可能遇到什么样的麻烦。

5 个答案:

答案 0 :(得分:7)

如果方法返回api - 调用者可能会在列表中添加一些奶酪。

这可能是一种不好的做法,因为您可能想要控制添加程序。

答案 1 :(得分:5)

因为

  • 您将使用具有单例模式的Collections.emptyList();来保存资源。
  • 它的类型安全
  • list是不可变的(不能修改)

还可以找到look at the API

  

返回空列表(不可变)。此列表是可序列化的。

     

此示例说明了获取空列表的类型安全方法:

 List<String> s = Collections.emptyList();
  

实施说明:此方法的实现无需为每个调用创建单独的List对象。 使用此方法的成本可能与使用同名字段相当。 (与此方法不同,该字段不提供类型安全性。)

答案 2 :(得分:5)

这里的想法更多是关于安全对象发布或共享,返回对可变列表的引用允许调用者改变原始列表,这通常是一个坏主意。如果列表或对象一般是不可变的,那么你不需要这样做,例如String是不可变的,因此共享它是安全的。

String getString(){
  return someString; // no need to copy
}

共享可变状态带来两个主要问题:

  1. 当事物可以从任何地方变异时,很难检查程序的正确性。
  2. 线程安全变得更难,因为它需要同步,这通常是困难且昂贵的。

答案 3 :(得分:2)

如果直接返回cheesesInStock,则会返回对您所对象所拥有的List的引用(而不是其副本);因此,获取此列表的人所做的任何更改都将反映在对象的内部表示中。例如:

List<Cheese> list = myObject.getCheeseList();
list.add(new Cheese()); // this also affects the list inside myObject

为了避免这种情况,最好使用new ArrayList<Cheese>(previousList)返回列表的副本。请注意,您可以使用Collections.unmodifiableList返回List的不可修改的视图,而不是返回新的List:这具有相同的目标 - 阻止调用代码修改内部表示对象。

返回Collections.emptyList();而不是返回new ArrayList<Cheese>(emptyList)的好处是可以避免创建另一个对象。此外,Collections.emptyList();代表不可变的List

答案 4 :(得分:2)

cheesesInStock列表可以在以后进行结构修改,但Collections.emptyList()返回一个空列表,以后不能对其进行结构修改。Collections.emptyList()返回EmptyList,其中一些函数是: -

public void add(int index, E element) {
    throw new UnsupportedOperationException();
}
public E get(int index) {
    throw new IndexOutOfBoundsException("Index: "+index);
}