简体   繁体   中英

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

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.

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.

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.

eg

//don't copy the first element 
List<String> list2 = list1.stream().skip(1).collect(Collectors.toList());
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;
}

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.

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 .

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

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

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

You can use addAll().

eg : wsListCopy.addAll(wsList);

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.

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

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

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

使用 list new ArrayList<>(list) 的内置构造函数

"

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM