177

I have a List<SomeBean> that is populated from a Web Service. I want to copy/clone the contents of that list into an empty list of the same type. A Google search for copying a list suggested me to use Collections.copy() method. In all the examples I saw, the destination list was supposed to contain the exact number of items for the copying to take place.

As the list I am using is populated through a web service and it contains hundreds of objects, I cannot use the above technique. Or I am using it wrong??!! Anyways, to make it work, I tried to do something like this, but I still got an IndexOutOfBoundsException.

List<SomeBean> wsList = app.allInOne(template);

List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList.size());   
Collections.copy(wsListCopy,wsList);
System.out.println(wsListCopy.size());

I tried to use the wsListCopy=wsList.subList(0, wsList.size()) but I got a ConcurrentAccessException later in the code. Hit and trial. :)

Anyways, my question is simple, how can I copy the entire content of my list into another List? Not through iteration, of course.

Mono Jamoon
  • 4,437
  • 17
  • 42
  • 64
  • 12
    Any copy will use iteration of course. You can hide it away but it will still be there. – Peter Lawrey Jan 14 '13 at 13:55
  • 2
    First of all: are you sure you need to copy that list? What is your motivation in doing that? – ppeterka Jan 14 '13 at 13:56
  • 2
    Yup, iteration is just hidden under that layers. But the comment was added to to prevent any iteration answers. :) – Mono Jamoon Jan 14 '13 at 13:56
  • @ppeterka I am performing operations on the list, like removeAll(). This causes the list to loss its original data. And "that data" is also required afterwards. – Mono Jamoon Jan 14 '13 at 13:59
  • What is the actual type of a list, which is returning by `app.allInOne(template)`? `ArrayList`? – Andremoniy Jan 14 '13 at 14:10
  • Do you want a [shallow copy or deep copy](https://en.wikipedia.org/wiki/Object_copying#Methods_of_copying)? – cellepo Nov 23 '18 at 19:55

14 Answers14

287

Just use this:

List<SomeBean> newList = new ArrayList<SomeBean>(otherList);

Note: still not thread safe, if you modify otherList from another thread, then you may want to make that otherList (and even newList) a CopyOnWriteArrayList, for instance -- or use a lock primitive, such as ReentrantReadWriteLock to serialize read/write access to whatever lists are concurrently accessed.

fge
  • 119,121
  • 33
  • 254
  • 329
  • 1
    Javadoc: http://docs.oracle.com/javase/1.4.2/docs/api/java/util/ArrayList.html#ArrayList(java.util.Collection) – lcguida Jan 14 '13 at 13:55
  • 7
    +1 if he is getting ConcurrentModifcationException, he has a concurrency issue he needs to fix first. – Peter Lawrey Jan 14 '13 at 13:55
  • @RickeshJohn not unless you modify `otherList` from another thread (you don't, do you?) – fge Jan 14 '13 at 13:57
  • 1
    @fge Since he also gets IndexOutOfBoundsException, I think removing objects in another thread is highly likely. – Peter Lawrey Jan 14 '13 at 13:59
  • 1
    Multiple threads!!!! All I am doing is a removeAll(anotherDistantList). And I am getting a the ConcurrentException. – Mono Jamoon Jan 14 '13 at 14:02
  • @PeterLawrey that is right... Linked to a thread-safe implementation. – fge Jan 14 '13 at 14:05
  • hi, could I ask what is the computation cost of initialising a list in this way? – Evil Washing Machine Feb 20 '15 at 17:18
  • 1
    Another thing: With this you don't actual copy inner List inside SomeBean objects. They are still pointing to the otherList inner lists. So be careful if you're going to edit inner lists – edoardotognoni Feb 27 '15 at 16:48
  • what if the source list is not an `ArrayList` and you want the target to be of the same implementation as the source ? – amphibient Mar 24 '15 at 22:43
  • @amphibient the particular implementation of your `List` should never be a concern; if it is you have a design issue which you have to solve first. – fge Mar 25 '15 at 06:37
  • 9
    Why is this answer getting so many points if the question mentioned "copy/clone"? This, as long as some other answers have nothing to do with cloning. The same references will be kept for the objects inside the collections whatever collection/stream specific utility-methods you use. – yuranos Oct 09 '16 at 21:05
  • 5
    The answer is wrong. The content is not copied. Only It's references. – The incredible Jan Apr 27 '18 at 11:03
  • Deep copy (which this Question asks for) info: https://stackoverflow.com/questions/715650/how-to-clone-arraylist-and-also-clone-its-contents – cellepo Aug 12 '18 at 04:17
43

This is a really nice Java 8 way to do it:

List<String> list2 = list1.stream().collect(Collectors.toList());

Of course the advantage here is that you can filter and skip to only copy of part of the list.

e.g.

//don't copy the first element 
List<String> list2 = list1.stream().skip(1).collect(Collectors.toList());
Apostolos
  • 10,033
  • 5
  • 24
  • 39
Dan
  • 9,681
  • 14
  • 55
  • 70
24
originalArrayList.addAll(copyArrayofList);

Please keep on mind whenever using the addAll() method for copy, the contents of both the array lists (originalArrayList and copyArrayofList) references to the same objects will be added to the list so if you modify any one of them then copyArrayofList also will also reflect the same change.

If you don't want side effect then you need to copy each of element from the originalArrayList to the copyArrayofList, like using a for or while loop. for deep copy you can use below code snippet.

but one more thing you need to do, implement the Cloneable interface and override the clone() method for SomeBean class.

public static List<SomeBean> cloneList(List<SomeBean> originalArrayList) {
    List<SomeBean> copyArrayofList = new ArrayList<SomeBean>(list.size());
    for (SomeBean item : list) copyArrayofList.add(item.clone());
    return copyArrayofList;
}
Divyesh Kanzariya
  • 3,629
  • 3
  • 43
  • 44
  • 3
    This is one of the few true Answers here, as it specifies #addAll makes a shallow copy, as well as how to deep copy. More details: https://stackoverflow.com/questions/715650/how-to-clone-arraylist-and-also-clone-its-contents – cellepo Aug 12 '18 at 04:14
9

Starting from Java 10:

List<E> oldList = List.of();
List<E> newList = List.copyOf(oldList);

List.copyOf() returns an unmodifiable List containing the elements of the given Collection.

The given Collection must not be null, and it must not contain any null elements.

Also, if you want to create a deep copy of a List, you can find many good answers here.

Oleksandr Pyrohov
  • 14,685
  • 6
  • 61
  • 90
8

I tried to do something like this, but I still got an IndexOutOfBoundsException.

I got a ConcurrentAccessException

This means you are modifying the list while you are trying to copy it, most likely in another thread. To fix this you have to either

  • use a collection which is designed for concurrent access.

  • lock the collection appropriately so you can iterate over it (or allow you to call a method which does this for you)

  • find a away to avoid needing to copy the original list.

Community
  • 1
  • 1
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
5

There is another method with Java 8 in a null-safe way.

List<SomeBean> wsListCopy = Optional.ofNullable(wsList)
    .map(Collection::stream)
    .orElseGet(Stream::empty)
    .collect(Collectors.toList());

If you want to skip one element.

List<SomeBean> wsListCopy = Optional.ofNullable(wsList)
    .map(Collection::stream)
    .orElseGet(Stream::empty)
    .skip(1)
    .collect(Collectors.toList());

With Java 9+, the stream method of Optional can be used

Optional.ofNullable(wsList)
    .stream()
    .flatMap(Collection::stream)
    .collect(Collectors.toList())
Nicolas Henneaux
  • 11,507
  • 11
  • 57
  • 82
2

I tried something similar and was able to reproduce the problem (IndexOutOfBoundsException). Below are my findings:

1) The implementation of the Collections.copy(destList, sourceList) first checks the size of the destination list by calling the size() method. Since the call to the size() method will always return the number of elements in the list (0 in this case), the constructor ArrayList(capacity) ensures only the initial capacity of the backing array and this does not have any relation to the size of the list. Hence we always get IndexOutOfBoundsException.

2) A relatively simple way is to use the constructor that takes a collection as its argument:

List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList);  
1

I was having the same problem ConcurrentAccessException and mysolution was to:

List<SomeBean> tempList = new ArrayList<>();

for (CartItem item : prodList) {
  tempList.add(item);
}
prodList.clear();
prodList = new ArrayList<>(tempList);

So it works only one operation at the time and avoids the Exeption...

T04435
  • 12,507
  • 5
  • 54
  • 54
1

You can use addAll().

eg : wsListCopy.addAll(wsList);

0

re: indexOutOfBoundsException, your sublist args are the problem; you need to end the sublist at size-1. Being zero-based, the last element of a list is always size-1, there is no element in the size position, hence the error.

Jorgesys
  • 124,308
  • 23
  • 334
  • 268
Jon Nelson
  • 421
  • 1
  • 4
  • 4
0

I can't see any correct answer. If you want a deep copy you have to iterate and copy object manually (you could use a copy constructor).

The incredible Jan
  • 741
  • 10
  • 17
  • This is one of the few true Answers here. More details: https://stackoverflow.com/questions/715650/how-to-clone-arraylist-and-also-clone-its-contents – cellepo Aug 12 '18 at 04:16
0

You should use the addAll method. It appends all of the elements in the specified collection to the end of the copy list. It will be a copy of your list.

List<String> myList = new ArrayList<>();
myList.add("a");
myList.add("b");
List<String> copyList = new ArrayList<>();
copyList.addAll(myList);
Tyler2P
  • 2,324
  • 26
  • 22
  • 31
0

just in case you use Lombok:

mark SomeBean with the following annotation:

@Builder(toBuilder = true, builderMethodName = "")

and Lombok will perform a shallow copy of objects for you using copy constructor:

inputList.stream()
         .map(x -> x.toBuilder().build())
         .collect(Collectors.toList());
Dan Serbyn
  • 105
  • 5
-3

subList function is a trick, the returned object is still in the original list. so if you do any operation in subList, it will cause the concurrent exception in your code, no matter it is single thread or multi thread.