2010-03-03 71 views
8

我有這個類:從參數分配集合的首選方式是什麼?

public MyClass { 
    public void initialize(Collection<String> data) { 
     this.data = data; // <-- Bad! 
    } 
    private Collection<String> data; 
} 

這顯然是不好的風格,因爲我引入一個共享的可變狀態。處理這個問題的首選方法是什麼?

  • 忽略它嗎?
  • 克隆集合?
  • ...?

編輯:解釋,爲什麼這是不好的,想象一下:

MyClass myObject = new MyClass(); 
List<String> data = new ArrayList<String>(); 
myObject.initialize(data); // myObject.data.size() == 0 
data.add("Test"); // myObject.data.size() == 1 

只是存儲參考構成的方式來注入數據的私有字段myObject.data,儘管它應該是完全私人的。

根據MyClass的性質,這可能會產生嚴重的影響。

+2

何時以及狀態如何改變?你的班級需要觀察變化嗎? – 2010-03-03 08:27:58

+0

@Jesse:爲這個問題增加了一個例子。 – 2010-03-03 08:39:26

回答

9

,最好的辦法是深克隆參數。出於性能原因,這通常是不可能的。最重要的是,並非所有對象都可以被克隆,因此深度複製可能會引發異常並導致各種頭痛。

下一個最好的辦法是一個「寫入時複製」克隆。在Java運行時中沒有對此的支持。

如果你認爲它可能是有人變異的收集,使用拷貝構造函數做一個淺拷貝:

this.data = new HashSet<String> (data); 

這將解決你的問題(因爲字符串是不可改變的),但它會失敗時的類型該集是可變的。

另一種解決方案是要始終使套一成不變的,只要你保存它們的地方:

Set<String> set = ... 
...build the set... 

// Freeze the set 
set = Collections.unmodifiableSet(set); 

// Now you can safely pass it elsewhere 
obj.setData (set); 

這裏的想法是儘快把收藏變成「值對象」成爲可能。任何想要更改集合的人都必須複製它,將其更改並保存回去。

在一個類中,你可以保持這個集合是可變的,並把它包裝在getter中(你應該這樣做)。

這種方法的問題:性能(但可能不像你期望的那麼糟糕)和紀律(如果你在某處忘記它,會中斷)。

+0

關於可變項目的好處! – 2010-03-03 08:52:45

+0

@DR:哎呀。固定。 – 2010-03-03 10:12:13

0

一個想法是將數據作爲字符串數組傳遞並在MyClass中創建Set。當然,MyClass應該測試輸入數據是否有效。無論如何,我相信這是一個很好的做法。

如果MyClass的MyClass的和自己的兩個主叫方實際上有Set<String>工作,那麼你可以考慮克隆集合。然而,集合需要以某種方式構建。我寧願把這個責任轉移到MyClass上。

3
  • 空檢查(如果你想限制空)
  • 無論是防守複印件(如果你不想共享狀態)
  • 或像你一樣(如果對數據的實時取景是非常有用的)

嚴重取決於您的要求。

編輯: 忽略不應該是選項。無聲的失敗是,一個調試噩夢。

1
public class Foo { 
    private final Collection collection = new ArrayList(); 
    public void initialise(final Collection collection) { 
     this.collection.addAll(collection); 
    } 
} 
1

對不起,沒有直接解決您的問題,但我絕不會直接將Collection傳遞給setXxx()bean setter方法。相反,我會做:

private final List<MyClass> theList; 

public void addXxx(MyClass item) { ... } 
public void removeXxx(MyClass item) { ... } // or index. 

public void Iterator<MyClass> iterateXxx() { 
    return Collections.unmodifiableList(theList).iterator(); 
} 

我會去防守複印/深克隆只有當我肯定會有使用它,沒有任何副作用,並以此爲速度,我不會與關注自己它,因爲在商業應用中,可靠性比速度優先10倍。 ;-)

相關問題