从参数中分配集合的首选方法是什么?

Dan*_*ski 8 java

我有这门课:

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

这显然是糟糕的风格,因为我引入了一个共享的可变状态.处理这个问题的首选方法是什么?

  • 忽略它?
  • 克隆收藏?
  • ...?

编辑:为了澄清为什么这是坏的,想象一下:

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

只是存储引用提供了一种将数据注入私有字段的方法myObject.data,尽管它应该是完全私有的.

根据其性质MyClass可能会产生严重影响.

Aar*_*lla 9

最好的方法是深度克隆参数.出于性能原因,这通常是不可能的.最重要的是,并非所有对象都可以克隆,因此深度复制可能会引发异常并导致各种头痛.

下一个最好的方法是"copy-on-write"克隆.Java运行时中不支持此功能.

如果您认为有人可能会改变集合,请使用复制构造函数执行浅表复制:

this.data = new HashSet<String> (data);
Run Code Online (Sandbox Code Playgroud)

这将解决您的问题(因为String是不可变的)但是当集合中的类型是可变的时它将失败.

另一种解决方案是,只要将它们存储在某处,就始终使这些集不可变:

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

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

// Now you can safely pass it elsewhere
obj.setData (set);
Run Code Online (Sandbox Code Playgroud)

这里的想法是尽快将集合转换为"价值对象".任何想要更改集合的人都必须复制它,更改它然后再保存.

在一个类中,你可以保持set可变并将它包装在getter中(无论如何你都应该这样做).

这种方法存在的问题:性能(但可能没有你预期的那么糟糕)和纪律(如果你忘了它就会​​中断).