2015-10-14 104 views
4

我正在阅读J. Bloch的有效Java,现在我在关于避免返回null s的部分,但返回空集合。这是该代码示例构成部分:创建集合的副本

// 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,我们可能会遇到什么样的麻烦。

+1

的方法评价_“//返回一个**副本的正确方式**收集的” _。你认为'返回奶酪inStock;'呢? –

回答

7

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

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

5

因为

  • 你会节省资源,Collections.emptyList();具有singletton模式。
  • 它是类型安全
  • 名单不变(不能修改)

也采取了look at the API你可以找到:

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

这个例子说明了类型安全的方式来获得一个空列表:

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

实现注意事项:此方法的实现不必为每次调用创建一个单独的List对象。 使用此方法很可能会使用类似名称的字段具有可比的成本。 (与此不同的方法,该字段不提供类型安全。)

5

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

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

共享可变状态带有两个主要的头痛:

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

如果直接返回cheesesInStock,你返回参照同List,你对象具有一个(而不是它的一个副本);因此获取此列表的人所做的任何更改都会反映在对象的内部表示中。例如:

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

要从此避免,这是一个很好的做法,返回列表的副本,而不是new ArrayList<Cheese>(previousList)。请注意,代替返回新的List,您也可以使用Collections.unmodifiableList返回List的不可修改视图:它具有相同的目标 - 防止调用代码修改对象的内部表示形式。

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

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); 
}