23

I need a shallow copy of an java ArrayList, should I use clone() or iterate over original list and copy elements in to new arrayList, which is faster ?

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
tech20nn
  • 729
  • 2
  • 6
  • 17
  • 1
    During entering the question, you should have seen a list of related question been popped up (the same list as you see in the right bottom column of this page). Did you peek around in them? Why weren't those answers sufficient? Please elaborate. – BalusC Apr 07 '10 at 13:56
  • I did go over the pop up. There was nothing related to performance in terms of ArrayList iterator vs clone(). – tech20nn Apr 07 '10 at 14:13

4 Answers4

59

No need to iterate:

List original = ...
List shallowCopy = new ArrayList(original);

http://java.sun.com/javase/6/docs/api/java/util/ArrayList.html#ArrayList%28java.util.Collection%29

Bart Kiers
  • 166,582
  • 36
  • 299
  • 288
  • 3
    however this is not threadsafe. (ended up here because I'm getting ConcurrentModificationException doing this) – Gubatron Oct 09 '17 at 22:57
14

Use clone(), or use the copy-constructor.

The copy-constructor makes additional transformation from the passed collection to array, while the clone() method uses the internal array directly.

Have in mind that clone() returns Object, so you will have to cast to List.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
  • Exactly I looked at the java.util.ArrayList source code and did find that the clone() uses Array.copyof, which would be far more efficient than looping over original ArrayList. public Object clone() { try { @SuppressWarnings("unchecked") ArrayList v = (ArrayList) super.clone(); v.elementData = Arrays.copyOf(elementData, size); v.modCount = 0; return v; } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(); } } – tech20nn Apr 07 '10 at 14:18
  • 2
    I wouldn't worry much about the efficiency. Using clone() is a pain; just use the conversion constructor as suggested. – Kevin Bourrillion Apr 07 '10 at 18:34
  • 2
    @Kevin Bourrillion why do you think using `clone()` is pain? Implementing `clone()` is pain, not using it. – Bozho Apr 07 '10 at 19:08
  • 4
    Typically, you never want to write a lot of code that depends on the implementation class, `ArrayList`; the universally agreed-on best practice is to limit your dependence to interface types like `List`. But you cannot clone a `List` without knowing exactly what implementation type (`ArrayList`, `LinkedList`, etc.) you can downcast it to first! Then, once you get the result, it's an `Object`, so you've got to cast that as well! On top of this, some implementations won't bother to swallow their own `CloneNotSupportedException`s. And worst yet, because this is so much more painful (cont.) – Kevin Bourrillion Apr 08 '10 at 05:13
  • 2
    ... than simple conversion constructors, many libraries just aren't going to bother playing the clone game at all. The community is largely fed up with all this. I suggest you just completely forget that the concept of cloning even exists, with the possible exception of occasionally cloning an array, which is convenient. Frankly, the situation is so bad that I'm shocked to hear anyone assert that using it is not a pain! – Kevin Bourrillion Apr 08 '10 at 05:16
  • @Kevin Bourrillion http://stackoverflow.com/questions/2597965/why-people-are-so-afraid-of-using-clone-on-collection-and-jdk-classes – Bozho Apr 08 '10 at 06:24
9

Instead of iterating manually you can use the copy constructor.

As for the speed difference between that and using clone():

  1. It doesn't matter
  2. Most likely there is none
  3. Do a benchmark for your specific system configuration and use case
Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • @Michael..Thanks. I checked the code for copy constructor. It has extra step to return copy internal array structure as Bozho mentioned. public ArrayList(Collection extends E> c) { elementData = c.toArray(); size = elementData.length; if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } – tech20nn Apr 07 '10 at 14:28
  • I like the universal "should I optimize?" thought pattern – Jan Šimbera Jan 05 '16 at 15:51
-3

the question says shallowcopy not deepcopy.Copying directly reference from one arraylist reference to another will also work right.Deep copy includes copy individual element in arraylist.

ArrayList<Integer> list=new ArrayList<Integer>();
list.add(3);
ArrayList<Integer> list1=list; //shallow copy...

Is there any problem in this ??

  • 3
    This is wrong. All this will make is that there will be two pointers to one physical `ArrayList` object in memory. Adding an `Integer` to one list makes the `Integer` appear also in the other list. That is not what we want. Shallow copy makes the underlying objects to share the same memory space, but the lists to have separate memory space. So if you modify one `Integer`, it will be modified in the both lists. But if you add an `Integer` into one list, it won't appear in the other one. Deep copy will not reflect any changes to anything at all in the other list. – Antimonit Nov 22 '14 at 13:51
  • list1 = list merely assigns the pointer to the ArrayList (named "list") to "list1" The original post asked for a "list1" with shallow copies of elements contained in "list" – ONE Jan 25 '23 at 00:38