Collections.unmodifiableList and defensive copy

Solution 1:

Yes, you understood it correctly. The idea is that the object returned by umodifiableCollection can't directly be changed, but could change through other means (effectively by changing the internal collection directly).

As long as something has access to the internal list, the "unmodifiable" collection could be changed.

That's why you usually construct a unmodifiable collection and make sure that nothing can ever get to the internal list:

Collection<Integer> myUmodifiableCollection = Collection.umodifiableCollection(Arrays.asList(1, 2, 3));

Since nothing ever gets a reference to the List created by asList, this is a truly unmodifiable collection.

The advantage of this approach is that you don't need to copy the original collection/list at all, which avoids using memory and computing power.

Guava provides the ImmutableCollection class (and its subclasses such as ImmutableList) which provide true immutable collections (usually by copying the source).

Solution 2:

Maybe did I misunderstand the meaning and if so what's the way to write a defensive copy of that collection?

Typically, you would use it that way:

private List<Integer> a1 = Arrays.asList(1, 2, 3);

public List<Integer> getUnmodifiable() {
    return Collections.unmodifiableList(a1);
}

Someone who calls getUnmodifiable and does not have access to the internal of your class (i.e. they can't acces the private variable a1), won't be able to modify the returned list.

Solution 3:

If you were looking to keep a1 mutable and make an immutable copy of it without Guava, this is one way you could do it.

    List<Integer> a1 = Arrays.asList(1, 2, 3);
    List<Integer> a2 = Collections.unmodifiableList(new ArrayList<>(a1));

Solution 4:

The idea is that you can't modify the list via a2.

Modifying the a1 list will indeed modify what you see in a2 - this is intended.

Just dont have a public way to access the list a1, and you should have what you want :)