HOWTO · Java

How to Copy ArrayList in Java

This article describes various techniques to copy an arraylist to another in Java

On this page

To copy an ArrayList into a separate list in Java, use the copy constructor when you want a new list initialized from the source. You can also use addAll(), a stream, or clone(). These approaches copy the list structure, not the objects stored in it: if an element is mutable, both lists still refer to that same object. The examples use the same names so you can compare how each method creates or fills the destination.

Choosing an ArrayList copy method

Choose new ArrayList<>(source) for the most direct way to create a new list from an existing collection. Use destination.addAll(source) when you already have a destination and want to append the source elements; clear it first only if replacing its contents is intended. A stream is useful when it already fits a transformation pipeline, but Collectors.toList() promises a List, not specifically an ArrayList. Wrap its result in the copy constructor when your code requires that concrete type. clone() is another shallow-copy option, though its Object return type requires a cast.

A shallow copy has an independent list structure: adding or removing an element in one list does not change the other list’s size or ordering. The element references are shared, however. For example, copying a list of mutable StringBuilder objects and then calling setLength(0) on an object obtained from the copy also changes what the source list sees. To copy mutable elements independently, create new element objects as well; none of the four methods below performs that deeper work. Strings in the examples are immutable, so they make the list operations easy to compare without suggesting that element mutation is copied.

Copy an ArrayList with its copy constructor

The collection constructor initializes a new ArrayList with the source elements in iteration order. It is the concise default when you need another list and do not need to transform the elements. The source remains a separate list, while references to any mutable elements are shared.

Run this example:

import java.util.ArrayList;

public class CopyArrayList {
  public static void main(String[] args) {
    ArrayList<String> names1 = new ArrayList<>();
    names1.add("Alan");
    names1.add("Alex");
    names1.add("Bob");
    names1.add("Bryan");
    names1.add("Cathy");
    names1.add("Drake");

    ArrayList<String> names2 = new ArrayList<>(names1);
    names2.forEach(System.out::println);
  }
}

Copy elements with addAll()

addAll() adds every element from the supplied collection to the end of the destination and returns whether the destination changed. It does not replace existing contents. For a fresh copy, start with an empty destination as below. If you pass a populated destination, its existing elements stay first and the source elements follow them. The operation also makes a shallow copy: the lists differ, but mutable elements are shared.

import java.util.ArrayList;

public class CopyArrayList {
  public static void main(String[] args) {
    ArrayList<String> names1 = new ArrayList<>();
    names1.add("Alan");
    names1.add("Alex");
    names1.add("Bob");
    names1.add("Bryan");
    names1.add("Cathy");
    names1.add("Drake");

    ArrayList<String> names2 = new ArrayList<>();
    names2.addAll(names1);
    names2.forEach(System.out::println);
  }
}

Copy an ArrayList with a stream

A stream can collect the source elements into a list, but Collectors.toList() does not guarantee a particular implementation. Do not cast that result to ArrayList: the returned list is only specified as a List, so such a cast is not safe. Constructing an ArrayList from the collected result gives you the concrete type explicitly. This still copies references rather than mutable elements.

import java.util.ArrayList;
import java.util.stream.Collectors;

public class CopyArrayList {
  public static void main(String[] args) {
    ArrayList<String> names1 = new ArrayList<>();
    names1.add("Alan");
    names1.add("Alex");
    names1.add("Bob");
    names1.add("Bryan");
    names1.add("Cathy");
    names1.add("Drake");

    ArrayList<String> names2 = new ArrayList<>(
        names1.stream().collect(Collectors.toList()));
    names2.forEach(System.out::println);
  }
}

Copy an ArrayList with clone()

ArrayList.clone() creates a shallow copy and has the declared return type Object. Cast the result to use it as an ArrayList; because the generic element type is erased, this cast is unchecked and normally produces a compiler warning. The @SuppressWarnings("unchecked") annotation on this example’s declaration suppresses that warning. Keep the cast limited to a list known to contain the expected element type. Prefer the copy constructor when you want to avoid this cast and warning.

import java.util.ArrayList;

public class CopyArrayList {
  public static void main(String[] args) {
    ArrayList<String> names1 = new ArrayList<>();
    names1.add("Alan");
    names1.add("Alex");
    names1.add("Bob");
    names1.add("Bryan");
    names1.add("Cathy");
    names1.add("Drake");

    @SuppressWarnings("unchecked")
    ArrayList<String> names2 = (ArrayList<String>) names1.clone();
    names2.forEach(System.out::println);
  }
}