How to Copy Java Collections List

How to copy Java Collections list

Calling

List<String> b = new ArrayList<String>(a);

creates a shallow copy of a within b. All elements will exist within b in the exact same order that they were within a (assuming it had an order).

Similarly, calling

// note: instantiating with a.size() gives `b` enough capacity to hold everything
List<String> b = new ArrayList<String>(a.size());
Collections.copy(b, a);

also creates a shallow copy of a within b. If the first parameter, b, does not have enough capacity (not size) to contain all of a's elements, then it will throw an IndexOutOfBoundsException. The expectation is that no allocations will be required by Collections.copy to work, and if any are, then it throws that exception. It's an optimization to require the copied collection to be preallocated (b), but I generally do not think that the feature is worth it due to the required checks given the constructor-based alternatives like the one shown above that have no weird side effects.

To create a deep copy, the List, via either mechanism, would have to have intricate knowledge of the underlying type. In the case of Strings, which are immutable in Java (and .NET for that matter), you don't even need a deep copy. In the case of MySpecialObject, you need to know how to make a deep copy of it and that is not a generic operation.


Note: The originally accepted answer was the top result for Collections.copy in Google, and it was flat out wrong as pointed out in the comments.

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

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.

How to copy java.util.list Collection

You may create a new list with an input of a previous list like so:

List one = new ArrayList()
//... add data, sort, etc
List two = new ArrayList(one);

This will allow you to modify the order or what elemtents are contained independent of the first list.

Keep in mind that the two lists will contain the same objects though, so if you modify an object in List two, the same object will be modified in list one.

example:

MyObject value1 = one.get(0);
MyObject value2 = two.get(0);
value1 == value2 //true
value1.setName("hello");
value2.getName(); //returns "hello"

Edit

To avoid this you need a deep copy of each element in the list like so:

List<Torero> one = new ArrayList<Torero>();
//add elements

List<Torero> two = new Arraylist<Torero>();
for(Torero t : one){
Torero copy = deepCopy(t);
two.add(copy);
}

with copy like the following:

public Torero deepCopy(Torero input){
Torero copy = new Torero();
copy.setValue(input.getValue());//.. copy primitives, deep copy objects again

return copy;
}

How to clone ArrayList and also clone its contents?

You will need to iterate on the items, and clone them one by one, putting the clones in your result array as you go.

public static List<Dog> cloneList(List<Dog> list) {
List<Dog> clone = new ArrayList<Dog>(list.size());
for (Dog item : list) clone.add(item.clone());
return clone;
}

For that to work, obviously, you will have to get your Dog class to implement the Cloneable interface and override the clone() method.

Copy of collection

If you need a deep copy you can do

public List<A> getList() {
return list.stream().map(A::copy).collect(toList());
}

The better solution is to not return the list in the first place. You can instead return something like.

public int getCount() { return list.size(); }

public String getASAt(int index) { return list.get(index).s; }

Now there is no way to modify the underlying A objects, nor do you need to copy them redundantly.

Why Collections.copy operation works on size of list instead of capacity of list?

According to the documentation:

copy

Copies all of the elements from one list into another. After the operation, the index of each copied element in the destination list will be identical to its index in the source list. The destination list must be at least as long as the source list. If it is longer, the remaining elements in the destination list are unaffected.
This method runs in linear time.

throws

IndexOutOfBoundsException - if the destination list is too small to contain the entire source List.
UnsupportedOperationException - if the destination list's list-iterator does not support the set operation.

So well... it's just the desired behavior. In case you want to add all elements of one list to another, you can List#addAll.

Creating a copy of a collection

If the method returns cheesesInStock - the caller may add some cheese to the list.

It is a bad practice as you may want to control adding procedure.

How to correctly copy collections with objects in Java

Changing state within a stream (as you are doing in peek) is an anti pattern. Don't do this.

I recommend something like this:

  public static List<Book> getListWithPrefixInName(List<Book> books) {
return books.stream()
.map(b -> Book.of(b.getId(), PREFIX + ": " + b.getName()))
.collect(toList());
}


Related Topics



Leave a reply



Submit