How can I clone an ArrayList
and also clone its items in Java?
For example I have:
ArrayList dogs = getDogs();
ArrayList
Java 8 provides a new way to call the copy constructor or clone method on the element dogs elegantly and compactly: Streams, lambdas and collectors.
Copy constructor:
List clonedDogs = dogs.stream().map(Dog::new).collect(toList());
The expression Dog::new
is called a method reference. It creates a function object which calls a constructor on Dog
which takes another dog as argument.
Clone method[1]:
List clonedDogs = dogs.stream().map(d -> d.clone()).collect(toList());
ArrayList
as the resultOr, if you have to get an ArrayList
back (in case you want to modify it later):
ArrayList clonedDogs = dogs.stream().map(Dog::new).collect(toCollection(ArrayList::new));
If you don't need to keep the original content of the dogs
list you can instead use the replaceAll
method and update the list in place:
dogs.replaceAll(Dog::new);
All examples assume import static java.util.stream.Collectors.*;
.
ArrayList
sThe collector from the last example can be made into a util method. Since this is such a common thing to do I personally like it to be short and pretty. Like this:
ArrayList clonedDogs = dogs.stream().map(d -> d.clone()).collect(toArrayList());
public static Collector> toArrayList() {
return Collectors.toCollection(ArrayList::new);
}
CloneNotSupportedException
:For this solution to work the clone
method of Dog
must not declare that it throws CloneNotSupportedException
. The reason is that the argument to map
is not allowed to throw any checked exceptions.
Like this:
// Note: Method is public and returns Dog, not Object
@Override
public Dog clone() /* Note: No throws clause here */ { ...
This should not be a big problem however, since that is the best practice anyway. (Effectice Java for example gives this advice.)
Thanks to Gustavo for noting this.
If you find it prettier you can instead use the method reference syntax to do exactly the same thing:
List clonedDogs = dogs.stream().map(Dog::clone).collect(toList());