Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Guava: ImmutableList magic of the copyOf() method

I would like to feel the 'magic power' of the copyOf() method of Guava guava-libraries.

There is small app that I use to check it.

Here is the documentation:

The JDK provides Collections.unmodifiableXXX methods, but in our opinion, these can be

  • unwieldy and verbose; unpleasant to use everywhere you want to make defensive copies
  • unsafe: the returned collections are only truly immutable if nobody holds a reference to the original collection

So, I try to build a model where "someone holds a reference to the original collection". Thus, working with a copy of collection I should not be worried about changing value on copy. But magic does not work so far (there are two tries: 1. copyOf(collection), 2. copyOf(iterator)):

import com.google.common.collect.ImmutableList;

import java.util.LinkedList;
import java.util.List;

class MyObject {    
    String name;    
    public MyObject(String name) {this.name = name;}    
    @Override
    public String toString() {
      return name;
    }    
}

public class ListUnsafe {

    List<MyObject> list = new LinkedList<MyObject>();    
    {
        list.add(new MyObject("a"));
        list.add(new MyObject("b"));
        list.add(new MyObject("c"));
    }

    public List<MyObject> getList() {
        return ImmutableList.copyOf(list);
    }

    public List<MyObject> getCopyIterator() {
        return ImmutableList.copyOf(list.iterator());
    }

    public static void main(String[] args) {

        ListUnsafe obj = new ListUnsafe();
        {
           MyObject ref = obj.list.get(0);

           List<MyObject> myList =  obj.getList();

           MyObject copyObj = myList.get(0);
           copyObj.name = "new";

           System.out.println("ref: " + ref);
        }

        obj = new ListUnsafe();
        {
            MyObject ref = obj.list.get(0);

            List<MyObject> myList =  obj.getCopyIterator();

            MyObject copyObj = myList.iterator().next();

            copyObj.name = "new";

            System.out.println("ref: " + ref);

        }

    }

}

The output:

ref: new
ref: new

It means that we changed original data. What we did not want.

Question

Why it does not do copy?
How it differs from unmodifiableXXX?

There is link to similar question:

The answer says about copyOf:

  • (from source) copyOf(Collection) instance doesn't create temporary ArrayList (copyOf(Iterable) and copyOf(Iterator) do so).
like image 409
ses Avatar asked May 27 '13 01:05

ses


People also ask

How do you make a collection immutable?

In Java 8 and earlier versions, we can use collection class utility methods like unmodifiableXXX to create immutable collection objects. If we need to create an immutable list then use the Collections. unmodifiableList() method.


1 Answers

  1. ImmutableList does not magically make the elements immutable; it's the list that cannot be modified, not the elements it contains.
  2. ImmutableList.copyOf makes a copy unless it is copying a list that is already an ImmutableList. If you call ImmutableList.copyOf(list) twice for the same immutable list, you will get two different copies.
like image 152
Louis Wasserman Avatar answered Nov 13 '22 03:11

Louis Wasserman