How to clone ArrayList and also clone its contents?

后端 未结 21 1931
小鲜肉
小鲜肉 2020-11-21 06:42

How can I clone an ArrayList and also clone its items in Java?

For example I have:

ArrayList dogs = getDogs();
ArrayList

        
21条回答
  •  梦如初夏
    2020-11-21 07:24

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

    Getting an ArrayList as the result

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

    Update the list in place

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


    Collector for ArrayLists

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

    [1] Note on 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.


    PS:

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

提交回复
热议问题