不再需要突变的时间点将 Java List 接口的对象转换为不可变的等价物会很好。 也就是说,客户端可以调用使 List 不可变的 freeze
方法。 对我来说,直接的好处是线程安全,没有
是否有提供此类功能的第三方接口或类?
Collections.unmodifiableList(List list)怎么样?
有一个 ImmutableList 类作为 Guava 库的一部分。您可以使用 copyOf
方法从现有Iterable
创建ImmutableList
,例如。
List<String> immutableList = ImmutableList.copyOf(list);
尝试使用 CopyOnWriteArrayList
。
CopyOnWriteArrayList 的行为与 ArrayList
类非常相似,不同之处在于当列表修改后,将创建一个新数组并丢弃旧数组,而不是修改基础数组。这意味着当调用者获得一个迭代器(即copyOnWriteArrayListRef.iterator() ),它在内部包含对基础 CopyOnWriteArrayList 对象的数组的引用,该数组是不可变的,因此可以是用于遍历,不需要在列表 copyOnWriteArrayListRef 上进行同步,也不需要clone() 遍历前的 copyOnWriteArrayListRef 列表(即没有并发修改的风险)和还提供更好的性能。
如果客户端仍然引用原始可变列表,则直接使用 Collections.unmodifiableList
是不够的。
我将创建一个委托列表实现,该实现将具有对原始可变列表(委托)的内部引用,并将所有方法调用转发到它。手动编写此类代码是一个PITA,但是例如Eclipse可以为您自动生成它。
然后,在调用 freeze
方法时,我将用 Collections.unmodifiableList
包装原始列表,以确保将来对FreezingList
的所有方法调用仅通过不可修改的视图转到原始委托。
为了使事情更安全,但不太灵活,您可以更改以下构造函数,而不是将原始列表传递给它(它仍然可以将原始可变列表的引用留给客户端),而是在内部实例化列表(例如作为ArrayList
)。
public class FreezingList<E> implements List<E> {
// the original list you delegate to (the delegate)
private List<E> list;
private boolean frozen = false;
public FreezingList(List<E> list) {
this.list = list;
}
public void freeze() {
if (!frozen) {
list = Collections.unmodifiableList(list);
frozen = true;
}
}
// all the delegating methods follow:
public int size() {
return list.size();
}
public E get(int index) {
return list.get(index);
}
// etc. etc.
}