How to copy a java.util.List into another java.util.List

JavaCollectionsCopy

Java Problem Overview


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.

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

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());

                

Solution 3 - Java

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 clone;
}

Solution 4 - Java

> 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.

Solution 5 - Java

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.

Solution 6 - Java

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())

Solution 7 - Java

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 wsListCopy=new ArrayList(wsList);

Solution 8 - Java

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...

Solution 9 - Java

You can use addAll().

eg : wsListCopy.addAll(wsList);

Solution 10 - Java

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.

Solution 11 - Java

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).

Solution 12 - Java

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);

Solution 13 - Java

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());

Solution 14 - Java

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMono JamoonView Question on Stackoverflow
Solution 1 - JavafgeView Answer on Stackoverflow
Solution 2 - JavaDanView Answer on Stackoverflow
Solution 3 - JavaDivyesh KanzariyaView Answer on Stackoverflow
Solution 4 - JavaPeter LawreyView Answer on Stackoverflow
Solution 5 - JavaOleksandr PyrohovView Answer on Stackoverflow
Solution 6 - JavaNicolas HenneauxView Answer on Stackoverflow
Solution 7 - JavaAbhay YadavView Answer on Stackoverflow
Solution 8 - JavaT04435View Answer on Stackoverflow
Solution 9 - Javasamaludheen cignesView Answer on Stackoverflow
Solution 10 - JavaJon NelsonView Answer on Stackoverflow
Solution 11 - JavaThe incredible JanView Answer on Stackoverflow
Solution 12 - JavaXGsm PrjView Answer on Stackoverflow
Solution 13 - JavaDan SerbynView Answer on Stackoverflow
Solution 14 - JavaweixingsunView Answer on Stackoverflow