Construct a deep copy of a List in Java
This post will discuss how to construct a deep copy of a List in Java.
1. Using Object.clone() method
To facilitate field-for-field copy of instances of a class, make that class implement the Cloneable interface and override its Object.clone() method. Then you can iterate through the list, clone each item by invoking the clone() method, and add it to the cloned list.
The clone() method calls the clone() method of its parent class to obtain the copy, and copies all mutable fields to the instance. This is demonstrated below:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; import java.util.List; class Student implements Cloneable { private String name; private LocalDate dob; public Student(String name, LocalDate dob) { this.name = name; this.dob = dob; } @Override public Object clone() throws CloneNotSupportedException { Student student = (Student) super.clone(); student.dob = LocalDate.from(this.dob); // date is mutable return student; } public void setDob(LocalDate dob) { this.dob = dob; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", dob=" + dob + '}'; } } public class Main { public static void main(String[] args) throws CloneNotSupportedException { List<Student> students = Arrays.asList( new Student("John", LocalDate.now()), new Student("Akon", LocalDate.now()), new Student("Tony", LocalDate.now().minusDays(2)) ); List<Student> clone = new ArrayList<>(); for (Student student : students) { clone.add((Student) student.clone()); } students.get(2).setDob(LocalDate.now()); for (Student student : clone) { System.out.println(student); } } } |
Output:
Student{name=’John’, dob=2017-12-13}
Student{name=’Akon’, dob=2017-12-13}
Student{name=’Tony’, dob=2017-12-11}
2. Implement clone() method
Another solution is to implement your own clone() method, instead of overriding the clone() method of the Object class. This can be effectively done using the Java 8 Stream, as shown below.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
import java.time.LocalDate; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; class Student { private String name; private LocalDate dob; public Student(String name, LocalDate dob) { this.name = name; this.dob = dob; } protected Student clone() { return new Student(this.name, LocalDate.from(this.dob)); } public void setDob(LocalDate dob) { this.dob = dob; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", dob=" + dob + '}'; } } public class Main { public static void main(String[] args) { List<Student> students = Arrays.asList( new Student("John", LocalDate.now()), new Student("Akon", LocalDate.now()), new Student("Tony", LocalDate.now().minusDays(2)) ); List<Student> clone = students.stream().map(Student::clone) .collect(Collectors.toList()); /* // Before Java 8, use below: List<Student> clone = new ArrayList<>(); for (Student student : students) { clone.add(student.clone()); } */ students.get(2).setDob(LocalDate.now()); for (Student student : clone) { System.out.println(student); } } } |
Output:
Student{name=’John’, dob=2017-12-13}
Student{name=’Akon’, dob=2017-12-13}
Student{name=’Tony’, dob=2017-12-11}
3. Copy Constructor
The copy constructor is the preferred way of copying objects in Java, instead of the clone() method. The copy constructor accepts just one argument that is another instance of the same class and creates a deep copy for all mutable fields.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
import java.time.LocalDate; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; class Student { private String name; private LocalDate dob; public Student(String name, LocalDate dob) { this.name = name; this.dob = dob; } public Student(Student student) { this.name = student.name; this.dob = LocalDate.from(student.dob); } public void setDob(LocalDate dob) { this.dob = dob; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", dob=" + dob + '}'; } } public class Main { public static void main(String[] args) { List<Student> students = Arrays.asList( new Student("John", LocalDate.now()), new Student("Akon", LocalDate.now()), new Student("Tony", LocalDate.now().minusDays(2)) ); List<Student> clone = students.stream().map(Student::new) .collect(Collectors.toList()); /* // Before Java 8, use below: List<Student> clone = new ArrayList<>(); for (Student student : students) { clone.add(new Student(student)); } */ students.get(2).setDob(LocalDate.now()); for (Student student : clone) { System.out.println(student); } } } |
Output:
Student{name=’John’, dob=2017-12-13}
Student{name=’Akon’, dob=2017-12-13}
Student{name=’Tony’, dob=2017-12-11}
That’s all about constructing a deep copy of a List in Java.
Thanks for reading.
To share your code in the comments, please use our online compiler that supports C, C++, Java, Python, JavaScript, C#, PHP, and many more popular programming languages.
Like us? Refer us to your friends and support our growth. Happy coding :)