在不再需要突变的时间点,将 Java 的 List 接口的对象转换为不可变的等价物会很好。也就是说,客户端可以调用freeze
使 List 不可变的方法。对我来说直接的好处是线程安全,没有内存开销深的复制。(编辑:如果人们认为所有线程都可以使用一个额外的不可变副本,那么他们是正确的。)
是否有提供此类功能的第三方接口或类?
在不再需要突变的时间点,将 Java 的 List 接口的对象转换为不可变的等价物会很好。也就是说,客户端可以调用freeze
使 List 不可变的方法。对我来说直接的好处是线程安全,没有内存开销深的复制。(编辑:如果人们认为所有线程都可以使用一个额外的不可变副本,那么他们是正确的。)
是否有提供此类功能的第三方接口或类?
作为 Guava 库的一部分,有一个ImmutableList类。您可以使用该方法从现有copyOf
的创建一个,例如。ImmutableList
Iterable
List<String> immutableList = ImmutableList.copyOf(list);
尝试使用CopyOnWriteArrayList
.
CopyOnWriteArrayList的行为与ArrayList
该类非常相似,只是在修改列表时,不是修改底层数组,而是创建一个新数组并丢弃旧数组。这意味着当调用者获得一个迭代器(即copyOnWriteArrayListRef.iterator())时,该迭代器在内部保存对底层 CopyOnWriteArrayList 对象数组的引用,该数组是不可变的,因此可以用于遍历而不需要在列表 copyOnWriteArrayListRef 上进行同步或需要在遍历之前克隆() copyOnWriteArrayListRef 列表(即没有并发修改的风险)并且还提供更好的性能。
如果客户端仍然有对原始可变列表的引用,则直接使用 ofCollections.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.
}