5

在不再需要突变的时间点,将 Java 的 List 接口的对象转换为不可变的等价物会很好。也就是说,客户端可以调用freeze使 List 不可变的方法。对我来说直接的好处是线程安全,没有内存开销深的复制。(编辑:如果人们认为所有线程都可以使用一个额外的不可变副本,那么他们是正确的。)

是否有提供此类功能的第三方接口或类?

4

4 回答 4

6

Collections.unmodifiableList(List list)怎么样?

于 2012-11-18T12:12:52.860 回答
3

作为 Guava 库的一部分,有一个ImmutableList类。您可以使用该方法从现有copyOf的创建一个,例如。ImmutableListIterable

List<String> immutableList = ImmutableList.copyOf(list);

于 2012-11-18T12:21:33.130 回答
1

尝试使用CopyOnWriteArrayList.

CopyOnWriteArrayList的行为与ArrayList该类非常相似,只是在修改列表时,不是修改底层数组,而是创建一个新数组并丢弃旧数组。这意味着当调用者获得一个迭代器(即copyOnWriteArrayListRef.iterator())时,该迭代器在内部保存对底层 CopyOnWriteArrayList 对象数组的引用,该数组是不可变的,因此可以用于遍历而不需要在列表 copyOnWriteArrayListRef 上进行同步或需要在遍历之前克隆() copyOnWriteArrayListRef 列表(即没有并发修改的风险)并且还提供更好的性能。

于 2012-11-18T12:13:00.593 回答
1

如果客户端仍然有对原始可变列表的引用,则直接使用 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.
}
于 2012-11-18T13:02:09.947 回答