[java] How to copy Java Collections list

I have an ArrayList and I want to copy it exactly. I use utility classes when possible on the assumption that someone spent some time making it correct. So naturally, I end up with the Collections class which contains a copy method.

Suppose I have the following:

List<String> a = new ArrayList<String>();
a.add("a");
a.add("b");
a.add("c");
List<String> b = new ArrayList<String>(a.size());

Collections.copy(b,a);

This fails because basically it thinks b isn't big enough to hold a. Yes I know b has size 0, but it should be big enough now shouldn't it? If I have to fill b first, then Collections.copy() becomes a completely useless function in my mind. So, except for programming a copy function (which I'm going to do now) is there a proper way to do this?

This question is related to java list collections copy

The answer is


As hoijui mentions. The selected answer from Stephen Katulka contains a comment about Collections.copy that is incorrect. The author probably accepted it because the first line of code was doing the copy that he wanted. The additional call to Collections.copy just copies again. (Resulting in the copy happening twice).

Here is code to prove it.

public static void main(String[] args) {

    List<String> a = new ArrayList<String>();
    a.add("a");
    a.add("b");
    a.add("c");
    List<String> b = new ArrayList<String>(a);

    System.out.println("There should be no output after this line.");

    // Note, b is already a shallow copy of a;
    for (int i = 0; i < a.size(); i++) {
        if (a.get(i) != b.get(i)) {
            System.out.println("Oops, this was a deep copy."); // Note this is never called.
        }
    }

    // Now use Collections.copy and note that b is still just a shallow copy of a
    Collections.copy(b, a);
    for (int i = 0; i < a.size(); i++) {
        if (a.get(i) != b.get(i)) {
            System.out.println("Oops, i was wrong this was a deep copy"); // Note this is never called.
        }
    }

    // Now do a deep copy - requires you to explicitly copy each element
    for (int i = 0; i < a.size(); i++) {
        b.set(i, new String(a.get(i)));
    }

    // Now see that the elements are different in each 
    for (int i = 0; i < a.size(); i++) {
        if (a.get(i) == b.get(i)) {
            System.out.println("oops, i was wrong, a shallow copy was done."); // note this is never called.
        }
    }
}

Just do:

List a = new ArrayList(); 
a.add("a"); 
a.add("b"); 
a.add("c"); 
List b = new ArrayList(a);

ArrayList has a constructor that will accept another Collection to copy the elements from


The answer by Stephen Katulka (accepted answer) is wrong (the second part). It explains that Collections.copy(b, a); does a deep copy, which it does not. Both, new ArrayList(a); and Collections.copy(b, a); only do a shallow copy. The difference is, that the constructor allocates new memory, and copy(...) does not, which makes it suitable in cases where you can reuse arrays, as it has a performance advantage there.

The Java standard API tries to discourage the use of deep copies, as it would be bad if new coders would use this on a regular basis, which may also be one of the reason why clone() is not public by default.

The source code for Collections.copy(...) can be seen on line 552 at: http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Core/Collections-Jar-Zip-Logging-regex/java/util/Collections.java.htm

If you need a deep copy, you have to iterate over the items manually, using a for loop and clone() on each object.


And if you are using google guava, the one line solution would be

List<String> b = Lists.newArrayList(a);

This creates a mutable array list instance.


the simplest way to copy a List is to pass it to the constructor of the new list:

List<String> b = new ArrayList<>(a);

b will be a shallow copy of a

Looking at the source of Collections.copy(List,List) (I'd never seen it before) it seems to be for coping the elements index by index. using List.set(int,E) thus element 0 will over write element 0 in the target list etc etc. Not particularly clear from the javadocs I'd have to admit.

List<String> a = new ArrayList<>(a);
a.add("foo");
b.add("bar");

List<String> b = new ArrayList<>(a); // shallow copy 'a'

// the following will all hold
assert a.get(0) == b.get(0);
assert a.get(1) == b.get(1);
assert a.equals(b);
assert a != b; // 'a' is not the same object as 'b'

private List<Item> cloneItemList(final List<Item> items)
    {
        Item[] itemArray = new Item[items.size()];
        itemArray = items.toArray(itemArray);
        return Arrays.asList(itemArray);
    }

The following output illustrates results of using copy constructor and Collections.copy():

Copy [1, 2, 3] to [1, 2, 3] using copy constructor.

Copy [1, 2, 3] to (smaller) [4, 5]
java.lang.IndexOutOfBoundsException: Source does not fit in dest
        at java.util.Collections.copy(Collections.java:556)
        at com.farenda.java.CollectionsCopy.copySourceToSmallerDest(CollectionsCopy.java:36)
        at com.farenda.java.CollectionsCopy.main(CollectionsCopy.java:14)

Copy [1, 2] to (same size) [3, 4]
source: [1, 2]
destination: [1, 2]

Copy [1, 2] to (bigger) [3, 4, 5]
source: [1, 2]
destination: [1, 2, 5]

Copy [1, 2] to (unmodifiable) [4, 5]
java.lang.UnsupportedOperationException
        at java.util.Collections$UnmodifiableList.set(Collections.java:1311)
        at java.util.Collections.copy(Collections.java:561)
        at com.farenda.java.CollectionsCopy.copyToUnmodifiableDest(CollectionsCopy.java:68)
        at com.farenda.java.CollectionsCopy.main(CollectionsCopy.java:20)

The source of full program is here: Java List copy. But the output is enough to see how java.util.Collections.copy() behaves.


b has a capacity of 3, but a size of 0. The fact that ArrayList has some sort of buffer capacity is an implementation detail - it's not part of the List interface, so Collections.copy(List, List) doesn't use it. It would be ugly for it to special-case ArrayList.

As MrWiggles has indicated, using the ArrayList constructor which takes a collection is the way to in the example provided.

For more complicated scenarios (which may well include your real code), you may find the collections within Guava useful.


If you want to copy an ArrayList, copy it by using:

List b = new ArrayList();
b.add("aa");
b.add("bb");

List a = new ArrayList(b);

To understand why Collections.copy() throws an IndexOutOfBoundsException although you've made the backing array of the destination list large enough (via the size() call on the sourceList), see the answer by Abhay Yadav in this related question: How to copy a java.util.List into another java.util.List


Strings can be deep copied with

List<String> b = new ArrayList<String>(a);

because they are immutable. Every other Object not --> you need to iterate and do a copy by yourself.


With Java 8 being null-safe, you could use the following code.

List<String> b = Optional.ofNullable(a)
                         .map(list -> (List<String>) new ArrayList<>(list))
                         .orElseGet(Collections::emptyList);

Or using a collector

List<String> b = Optional.ofNullable(a)
                         .map(List::stream)
                         .orElseGet(Stream::empty)
                         .collect(Collectors.toList())

Copy isn't useless if you imagine the use case to copy some values into an existing collection. I.e. you want to overwrite existing elements instead of inserting.

An example: a = [1,2,3,4,5] b = [2,2,2,2,3,3,3,3,3,4,4,4,] a.copy(b) = [1,2,3,4,5,3,3,3,3,4,4,4]

However I'd expect a copy method that would take additional parameters for the start index of the source and target collection, as well as a parameter for count.

See Java BUG 6350752


Every other Object not --> you need to iterate and do a copy by yourself.

To avoid this implement Cloneable.

public class User implements Serializable, Cloneable {

    private static final long serialVersionUID = 1L;

    private String user;
    private String password;
    ...

    @Override
    public Object clone() {
        Object o = null;
        try {
          o = super.clone();
        } catch(CloneNotSupportedException e) {
        }
        return o;
     }
 }

....

  public static void main(String[] args) {

      List<User> userList1 = new ArrayList<User>();

      User user1 = new User();
      user1.setUser("User1");
      user1.setPassword("pass1");
      ...

      User user2 = new User();
      user2.setUser("User2");
      user2.setPassword("pass2");
      ...

      userList1 .add(user1);
      userList1 .add(user2);

      List<User> userList2 = new ArrayList<User>();


      for(User u: userList1){
          u.add((User)u.clone());
      }

      //With this you can avoid 
      /*
        for(User u: userList1){
            User tmp = new User();
            tmp.setUser(u.getUser);
            tmp.setPassword(u.getPassword);
            ...
            u.add(tmp);               
        }
       */

  }

Why dont you just use addAll method:

    List a = new ArrayList();
         a.add("1");
         a.add("abc");

    List b = b.addAll(listA);

//b will be 1, abc

even if you have existing items in b or you want to pend some elements after it, such as:

List a = new ArrayList();
     a.add("1");
     a.add("abc");

List b = new ArrayList();
     b.add("x");
     b.addAll(listA);
     b.add("Y");

//b will be x, 1, abc, Y

List b = new ArrayList(a.size())

doesn't set the size. It sets the initial capacity (being how many elements it can fit in before it needs to resize). A simpler way of copying in this case is:

List b = new ArrayList(a);

Most answers here do not realize the problem, the user wants to have a COPY of the elements from first list to the second list, destination list elements are new objects and not reference to the elements of original list. (means changing an element of second list should not change values for corresponding element of source list.) For the mutable objects we cannot use ArrayList(Collection) constructor because it will simple refer to the original list element and will not copy. You need to have a list cloner for each object when copying.


Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to list

Convert List to Pandas Dataframe Column Python find elements in one list that are not in the other Sorting a list with stream.sorted() in Java Python Loop: List Index Out of Range How to combine two lists in R How do I multiply each element in a list by a number? Save a list to a .txt file The most efficient way to remove first N elements in a list? TypeError: list indices must be integers or slices, not str Parse JSON String into List<string>

Examples related to collections

Kotlin's List missing "add", "remove", Map missing "put", etc? How to unset (remove) a collection element after fetching it? How can I get a List from some class properties with Java 8 Stream? Java 8 stream map to list of keys sorted by values How to convert String into Hashmap in java How can I turn a List of Lists into a List in Java 8? MongoDB Show all contents from all collections Get nth character of a string in Swift programming language Java 8 Distinct by property Is there a typescript List<> and/or Map<> class/library?

Examples related to copy

Copying files to a container with Docker Compose Copy filtered data to another sheet using VBA Copy output of a JavaScript variable to the clipboard Dockerfile copy keep subdirectory structure Using a batch to copy from network drive to C: or D: drive Copying HTML code in Google Chrome's inspect element What is the difference between `sorted(list)` vs `list.sort()`? How to export all data from table to an insertable sql format? scp copy directory to another server with private key auth How to properly -filter multiple strings in a PowerShell copy script