2010-03-03 46 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倍。 ;-)

相关问题