190

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.

6
  • 12
    Any copy will use iteration of course. You can hide it away but it will still be there. Commented Jan 14, 2013 at 13:55
  • 2
    First of all: are you sure you need to copy that list? What is your motivation in doing that? Commented Jan 14, 2013 at 13:56
  • 2
    Yup, iteration is just hidden under that layers. But the comment was added to to prevent any iteration answers. :) Commented Jan 14, 2013 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. Commented Jan 14, 2013 at 13:59
  • What is the actual type of a list, which is returning by app.allInOne(template)? ArrayList? Commented Jan 14, 2013 at 14:10

15 Answers 15

305

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.

Sign up to request clarification or add additional context in comments.

14 Comments

+1 if he is getting ConcurrentModifcationException, he has a concurrency issue he needs to fix first.
@fge Since he also gets IndexOutOfBoundsException, I think removing objects in another thread is highly likely.
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.
The answer is wrong. The content is not copied. Only It's references.
|
47

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

5 Comments

is the resulting list a deep-copy or shallow copy of the original list?
A shallow copy.
This, sadly, also is not thread safe. Assuming list is changed while the collector is running, a ConcurrentModificationException is thrown.
@Dan, How to skip copying the last element?
@chandresh to skip copying the last element, you would just use .limit(list1.size() - 1)
28
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;
}

1 Comment

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: stackoverflow.com/questions/715650/…
16

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.

Comments

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.

Comments

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

Comments

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 Comment

This is a shallow copy, which will work fine if you are not updating any of the elements present in the lists. If the List is of Integer or such types, then this is fine. But if it's a complex object, where the value of the object might change in future iterations then both the lists will be impacted. This depends on the use-case, it can act as a requirement or bug w.r.t. the use-case.
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...

Comments

1

You can use addAll().

eg : wsListCopy.addAll(wsList);

1 Comment

This is a shallow copy, which will work fine if you are not updating any of the elements present in the lists. If the List is of Integer or such types, then this is fine. But if it's a complex object, where the value of the object might change in future iterations then both the lists will be impacted. This depends on the use-case, it can act as a requirement or bug w.r.t. the use-case.
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.

Comments

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

1 Comment

This is one of the few true Answers here. More details: stackoverflow.com/questions/715650/…
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);

Comments

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

Comments

0

Java 10 provide one feature like How to copy one collection to another collection

copyOf() is used to simple copy a collection(List,Set,Map);

Syntax

List<E> list=new ArrayList<>();

List<E> li2=List.copyOf(list);

Rule

  1. This method return immutable collection.
  2. If you want to modifie you got java.lang.UnsupportedOperationException.
  3. Null value not allowed
List<SomeBean> wsList = app.allInOne(template);

List<SomeBean> wsListCopy=List.copyOf(wsList);

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.