简体   繁体   中英

Unmodifiable List of modifiable objects

Let's say we have got a List<List<String>> and want to make it completely unmodifiable. Simply passing it to a Collection.unmodifiableList would not suffice because the inner Lists can still be modified.

I would go with the following approach:

List<List<String>> someList;

Make it unmodifiable:

List<List<String>> tempList = new ArrayList<>();
for(List<String> strList : someList) {
    tempList.add(Collections.unmodifiableList(strList));
}
List<List<String>> safeList = Collections.unmodifiableList(tempList);

Is this approach okay?

This approach should work, as long as you don't keep references to the original, modifiable, lists. Such references could modify the lists wrapped by the unmodifiable lists.

The way to achieve immutability is to create defensive copies.

Data in

Whenever a mutable object is passed to your method(s), you create a deep copy of it. This should be the first thing you do, even before you check validity, if you want maximum security.

Wrapping a list into a Collections.unmodifiableList() isn't going to work here because there's no guarantee that the underlying list won't be modified by a third party. In other words, you're not in control of the instance.

A good way of creating immutable copies of lists is by using Google Guava's ImmutableList.copyOf() method, but remember that you need a deep copy, so you need to create immutable copies of the lists within the main list.

Data out

whenever you return a value, you make another defensive copy, so that changes to the returned object don't reflect back. Here you can use unmodifiable wrappers (eg ImmutableList.of() ) on your lists because you're holding the only reference to the original list.

If you do both (copy on the way in, copy/wrap on the way out), your code will be safe and correct. Any other solution and no such general guarantees can be given, your code may or many not be correct.

I feel it doesnot work:-

    List<List<String>> someList = new ArrayList<>();

            List<String> l1 = new ArrayList<String>();
            List<String> l2 = new ArrayList<String>();

            l1.add("STR1");
            l1.add("STR2");
            l1.add("STR3");

            l2.add("STR4");
            l2.add("STR5");
            l2.add("STR6");

            someList.add(l1);
            someList.add(l2);

            List<List<String>> tempList = new ArrayList<>();
            for(List<String> strList : someList) {
                tempList.add(Collections.unmodifiableList(strList));
            }
            List<List<String>> safeList = Collections.unmodifiableList(tempList);

            l1.add("STR7"); // The inner list reference is modified which causes the 
safelist internal structure to get changed

            for(List<String> safeInnerList : safeList) {
                System.out.println(safeInnerList);

            }

The below code should do :-

            List<List<String>> tempList = new ArrayList<>();
            for(List<String> strList : someList) {
                tempList.add(new ArrayList<>(strList));
            }
            List<List<String>> safeList = Collections.unmodifiableList(tempList);

Here goes the test for this :-

List<List<String>> someList = new ArrayList<>();

        List<String> l1 = new ArrayList<String>();
        List<String> l2 = new ArrayList<String>();

        l1.add("STR1");
        l1.add("STR2");
        l1.add("STR3");

        l2.add("STR4");
        l2.add("STR5");
        l2.add("STR6");

        someList.add(l1);
        someList.add(l2);

        List<List<String>> tempList = new ArrayList<>();
        for(List<String> strList : someList) {
            tempList.add(new ArrayList<>(strList));
        }
        List<List<String>> safeList = Collections.unmodifiableList(tempList);

        l1.add("STR7"); // The inner list reference is modified this doesnot cause the safelist internal structure to get changed

        for(List<String> safeInnerList : safeList) {
            System.out.println(safeInnerList);
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM