2011-05-13 59 views
9

我很好奇,從可變類返回對象的集合時,什麼被認爲是一個更好的做法:在Java中返回內部集合的最佳做法是什麼?

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

我一直認爲在包裝不可修改的內部集合是最好的方法,因爲我沒看到這是造成創建副本開銷的原因。然而,我發現,內部對列表所做的任何更改都會暴露給客戶,這讓我感到不好。

回答

5

我不認爲這是一個簡單的「最佳實踐」答案。這實際上取決於您願意花費多少機器資源來防止違反類數據抽象邊界。這取決於你實際嘗試緩解的風險;例如它是簡單的(非併發)錯誤,併發錯誤還是信息泄漏。

的選項有:

  • 什麼都不做;即按原樣返回集合。
  • 返回包裝在不可變包裝類中的集合。
  • 返回集合的淺表副本。
  • 返回集合的深層副本。

除了複製的直接成本之外,其他與性能有關的因素還包括內存使用率和垃圾產生以及對併發性的影響。例如,如果多個線程正在更新集合和/或「獲取」集合,那麼創建集合的副本通常需要鎖定集合......這可能會使操作成爲併發瓶頸。

總之,您需要平衡對未採取預防措施的潛在或實際風險和成本的成本/性能影響。

1

我喜歡做後者,但使用.clone()方法。

+0

後一種方法使用新的ArrayList或使用.clone()是減少併發問題的正確方法。 Collections.unmodifiableList()增加了多線程環境中可能發生的併發問題。 – 2011-05-13 01:15:35

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

現在,你會看到列表1中加入! list2不是。

相關問題