我有许多在内部使用私有集或列表的Java类。我希望能够使用get ... List()方法返回这些集/列表。
我正在考虑的替代方案:
Collections.unmodifiableList(partitions);
哪一种是解决此问题的最常见/最佳方式?
答案 0 :(得分:4)
这里有许多方面需要考虑。正如其他人已经指出的那样,最终的决定取决于你的意图,但是关于这三个选项的一些一般性陈述:
<强> 1。返回对内部对象的引用
这可能会带来问题。当你这样做时,你几乎不可能保证一致的状态。调用者可能会获取列表,然后做一些讨厌的事情
List<Element> list = object.getList();
list.clear();
list.add(null);
...
可能没有恶意意图,但是不小心,因为他假设安全/允许这样做。
<强> 2。构建一个新的集/列表并填写(这似乎是不好的做法?)
这一般不是一种“坏习惯”。无论如何,它是API设计方面迄今为止最安全的解决方案。这里唯一需要注意的是,可能存在性能损失,具体取决于几个因素。例如。列表中包含多少元素,以及如何使用返回的列表。一些(可疑?)模式就像这个
for (int i=0; i<object.getList().size(); i++)
{
Element element = object.getList().get(i);
...
}
可能变得非常昂贵(尽管有人可能会争辩说,在这种特殊情况下,用户的错误是这样实现的,一般问题仍然有效)
第3。使用Collections.unmodifiableList(partitions);
这是我个人经常使用的。它在API设计意义上是安全的,与复制列表相比,其开销只有微不足道。但是,调用者在获得对它的引用之后知道该列表是否可能发生变化是很重要的。
这导致......
文档该方法正在做什么!不要写这样的评论
/**
* Returns the list of elements.
*
* @return The list of elements.
*/
public List<Element> getList() { ... }
相反,请指定您可以确定列表的内容。例如
/**
* Returns a copy of the list of elements...
*/
或
/**
* Returns an unmodifiable view on the list of elements...
*/
就个人而言,我总是在为这种文档提供的两个选项之间徘徊:
例如,我经常写这样的文档:
/**
* Returns an unmodifiable view on the list of elements.
* Changes in this object will be visible in the returned list.
*/
第二句是关于行为的明确的绑定声明。调用者知道这一点重要。对于并发应用程序(并且大多数应用程序以某种方式并发),这意味着调用者 认为列表可能在获得后同时更改引用,当迭代列表时发生更改时,可能会导致ConcurrentModificationException
。
但是,此类详细规范限制了之后更改实施的可能性。如果您以后决定返回内部列表的副本,则行为将以不兼容的方式更改。
因此,有时我也明确指定未指定行为:
/**
* Returns an unmodifiable list of elements. It is unspecified whether
* changes in this object will be visible in the returned list. If you
* want to be informed about changes, you may attach a listener to this
* object using this-and-that method...
*/
当您打算创建公共API时,这些问题主要是不重要的。一旦您以某种方式实现它,人们将以一种或另一种方式依赖行为。
所以回到第一点:它总是取决于你想要达到的目标。
答案 1 :(得分:2)
您的决定应基于一件事(主要是)
允许其他方法修改原始集合吗?
是:返回内部对象的引用。
否:
答案 2 :(得分:2)
return a reference to the internal object
在这种情况下,接收方端可以修改可能不需要的对象集或列表。如果您允许用户修改对象的状态,那么这是最简单的方法。
construct a new set/list and fill it up (this seems bad practice?)
这是示例浅层复制,其中集合对象不可修改,但对象将使用相同。因此,对象状态的任何变化都会影响实际的集合。
use Collections.unmodifiableList(partitions);
在这种情况下,它返回指定列表的不可修改视图。该方法允许模块为用户提供&#34;只读&#34;访问内部列表。在您希望保持对象的状态安全的情况下,这可以用作最佳实践。
答案 3 :(得分:1)
我认为最好的解决方案是返回一个不可修改的列表。如果与新列表的构造相比较,则返回原始列表的不可修改的“代理”可以使客户端不会隐式地生成许多不必要的列表。另一方面,如果客户端确实需要一个可修改的列表,那么让它自己创建一个新的列表。
您仍需要考虑的问题是列表中包含的对象可能会被修改。 Java中没有便宜且简单的const-correctness。
答案 4 :(得分:0)
第二种选择绝对是正确的选择。
其他两个选项取决于您的要求。