How to create a deep unmodifiable collection?

别说谁变了你拦得住时间么 提交于 2019-12-21 03:42:48

问题


I often make a collection field unmodifiable before returning it from a getter method:

private List<X> _xs;
....
List<X> getXs(){
  return Collections.unmodifiableList(_xs);
}

But I can't think of a convenient way of doing that if the X above is itself a List:

private List<List<Y>> _yLists;
.....
List<List<Y>> getYLists() {
  return Collections.unmodifiableList(_yLists);
}

The problem in the above is of course that though the client cannot modify the List of lists, it can add/delete Y objects from the embedded lists.

Any thoughts?


回答1:


The best I could come up with uses ForwardingList from Google Collections. Comments are welcome.

private static <T> List<List<T>> unmodifiableList2(final List<List<T>> input) {
    return Collections.unmodifiableList(new ForwardingList<List<T>>() {
        @Override protected List<List<T>> delegate() {
            return Collections.unmodifiableList(input);
        }
        @Override public List<T> get(int index) {
            return Collections.unmodifiableList(delegate().get(index));
        }
    });
}



回答2:


unfortunately, there is no easy way to get deep const-ness in java. you would have to hack around it by always making sure that the list inside the list is also unmodifiable.

i'd be interested too to know any elegant solution.




回答3:


The clojure collections (map, set, list, vector) can all be nested and are immutable by default. For pure java, there is this library:

http://code.google.com/p/pcollections/




回答4:


If you look at the implementation of the Collections.unmodifiable*(...) methods, you can see that they just wrap the collection. Doing a deep utility in same way should be doable.

The downside of this is that it adds extra method call to the collection access and so affects performance.




回答5:


If your only goal here is to enforce encapsulation, a classic solution is to use clone() or similar to return a structure that is not the internal state of the object. This obviously only works if all the objects can be cloned, and if the copied structure is small enough.

If this is a fairly commonly used data structure, another option is to make the API that accesses it more concrete, so that you have more detailed control over the specific calls. Writing your own List implementation, as above is one way to do this, but if you can narrow down the calls to specific use cases, you can expose specific access APIs instead of the List interface.




回答6:


Just in case someone is interested here is a simple solution:

    public List<List<Double>> toUnmodifiable(List<List<Double>> nestedList) {
        List<List<Double>> listWithUnmodifiableLists = new ArrayList<>();
            for (List<Double> list : nestedList) {              
                listWithUnmodifiableLists
                    .add(Collections.unmodifiableList(list));
            }
        return Collections.unmodifiableList(listWithUnmodifiableLists);
    }

This can be used for example as a solution if u want to expose a list with a getList() method, you can return: toUnmodifiable(mNestedList), where mNestedList is the private list in the class.

I personally found this useful when implementing a class used for parsing with GSON in Android, since it doesn't make sense to be able to modify a response, in this case the de-serialized json, I used this method as a way to expose the list with a getter and made sure the list wont be modified.



来源:https://stackoverflow.com/questions/415967/how-to-create-a-deep-unmodifiable-collection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!