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?
Calling
creates a shallow copy of
a
withinb
. All elements will exist withinb
in the exact same order that they were withina
(assuming it had an order).Similarly, calling
also creates a shallow copy of
a
withinb
. If the first parameter,b
, does not have enough capacity (not size) to contain all ofa
's elements, then it will throw anIndexOutOfBoundsException
. The expectation is that no allocations will be required byCollections.copy
to work, and if any are, then it throws that exception. It's an optimization to require the copied collection to be preallocated (b
), but I generally do not think that the feature is worth it due to the required checks given the constructor-based alternatives like the one shown above that have no weird side effects.To create a deep copy, the
List
, via either mechanism, would have to have intricate knowledge of the underlying type. In the case ofString
s, which are immutable in Java (and .NET for that matter), you don't even need a deep copy. In the case ofMySpecialObject
, you need to know how to make a deep copy of it and that is not a generic operation.Note: The originally accepted answer was the top result for
Collections.copy
in Google, and it was flat out wrong as pointed out in the comments.b
has a capacity of 3, but a size of 0. The fact thatArrayList
has some sort of buffer capacity is an implementation detail - it's not part of theList
interface, soCollections.copy(List, List)
doesn't use it. It would be ugly for it to special-caseArrayList
.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.
Just do:
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);
andCollections.copy(b, a);
only do a shallow copy. The difference is, that the constructor allocates new memory, andcopy(...)
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.htmIf you need a deep copy, you have to iterate over the items manually, using a for loop and clone() on each object.
the simplest way to copy a List is to pass it to the constructor of the new list:
b
will be a shallow copy ofa
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. usingList.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.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:
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.
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.
Why dont you just use
addAll
method:even if you have existing items in b or you want to pend some elements after it, such as:
If you want to copy an ArrayList, copy it by using:
Strings can be deep copied with
because they are immutable. Every other Object not --> you need to iterate and do a copy by yourself.
Every other Object not --> you need to iterate and do a copy by yourself.
To avoid this implement Cloneable.
....
The following output illustrates results of using copy constructor and Collections.copy():
The source of full program is here: Java List copy. But the output is enough to see how java.util.Collections.copy() behaves.
With Java 8 being null-safe, you could use the following code.
Or using a collector
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
And if you are using google guava, the one line solution would be
This creates a mutable array list instance.
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