저번 글에서는 List.CopyOf에 대해서 다뤘는데요.
이전 글: https://zerotoinfinite.tistory.com/9
Java - List의 복사 (2): List.copyOf
리스트의 복사 두 번째인 List.copyOf에 대해 알아보자! 저번 글에서 Collections.unmodifiableList에 대해 다뤘으므로 이 글을 읽기 전에 먼저 읽으시면 이해가 잘 될 겁니다! 이전 글: https://zerotoinfinite.tisto
zerotoinfinite.tistory.com
오늘은 리스트 내 원소(객체)들 까지 복사하여 새로운 리스트를 만드는 법에 대해 알아보겠습니다!!
방법만 아는 것은 의미가 없다고 생각합니다. 언제 어느 상황에 리스트 내 객체까지 복사해야하는지를 알아야됩니다.
리스트보다는 리스트가 담고 있는 '항목'에 대해 이야기하는 거였어요 :)
리뷰어님이 남겨주신 코멘트다. 이말의 뜻은 리스트 자체를 복사하는 것이 아닌, 리스트 내의 객체들까지 복사하라는 것이다.
왜 Collection내의 객체까지 복사를 해야할까?
1. 서로 다른 List에서 같은 객체를 참조할 때 객체의 상태를 변화시키면 둘 다 영향을 받는다.
누군가는 질문할 수 있다.
리스트 내의 객체까지 모두 복사하면 메모리 낭비 아닌가요?
메모리 낭비일 수도 있고 아닐 수도 있다. 그럼 언제 객체까지 복사해야하는지, 하지 않아도 되는지 알아보자.
리스트만 복사를 하면 두 리스트 모두 같은 객체를 참조한다. 만약 한쪽에서 객체의 상태를 바꾼다면 ?
객체를 바꾸지 않은 한쪽은 자신이 바꾸지도 않았는데 내가 참조하고 있던 객체의 상태가 바뀌어버린다.
이러한 상황을 원하지 않는다면 리스트가 담고 있는 객체를 모두 복사해야 한다.
밑과 같은 상황을 만들고 싶은 것이다.
그러면 한쪽에서 객체를 수정하여도 다른 리스트는 다른 객체를 참조하고 있기 때문에 영향을 받지 않는다.
그렇다면 항상 리스트를 복사할 때 내부의 객체들도 복사를 해야하는 것일까 ?
내 대답은 NO이다.
만약, 리스트 내의 객체가 불변 객체 즉, 상태가 변하지 않는 객체라면 개별적인 객체 복사를 진행하지 않아도 된다고 생각한다.
객체의 상태가 애초에 변하지 않는다면, 애초에 객체의 상태가 변화할 일이 없기 때문에 서로 다른 리스트에서 같은 객체를 참조해도 괜찮다.
그러므로 각자의 상황에 맞게 객체까지 복사할지 말지를 결정하면 된다!
리스트내의 객체까지 복사하는 방법
// 원본 리스트
List<Car> cars = List.of(new Car("firstCar"), new Car("secondCar"));
// 복사된 리스트
List<Car> deepCopyCars = cars.stream()
.map(car -> new Car(car.getName()))
.toList();
원본 리스트 내의 객체의 필드를 모두 복사하여 새로운 객체를 만든 뒤 리스트에 담아주면 된다!
getter를 쓰고 싶지 않다면, Car내에 복사생성자를 정의해도 괜찮다 !
밑과 같은 방식으로 말이다.
public class Car {
private final String name;
public Car(String name) {
this.name = name;
}
public Car(Car car) {
this.name = car.getName();
}
public String getName() {
return name;
}
}
위와 같이 복사생성자를 정의하면 다음과 같이 바꿀 수도 있다.
List<Car> deepCopyCars = cars.stream()
.map(Car::new)
.toList();
Stream API를 사용하지 않고 리스트를 순회하는 방법도 있다.
List<Car> cars = List.of(new Car("firstCar"), new Car("secondCar"));
List<Car> deepCopyCars = new ArrayList<>();
for (Car car : cars) {
deepCopyCars.add(new Car(car));
}
회고
무엇이든 쓰는 방법만 알고 있다고 전부 아는 것은 아니다.
어떤 상황에서 어떤 방법을 써야될지를 아는 것이 진짜 아는 것이다.
근거를 갖고 선택하는 일이 바로 우리가 해야 할 일이 아닐까?
항상 주어진 상황과 이를 타개할 수 있는 방법, 그리고 Trade-off까지 생각하는 습관을 갖자 !
잘못된 내용이 전파되는 것을 경계하고 있기 때문에 최대한 Oracle docs와 내부 구현 코드를 보고 작성한 글입니다. 혹시라도 틀린 내용이 있다면 댓글 부탁드립니다. 감사합니다:)
'프로그래밍 언어 > Java' 카테고리의 다른 글
Java - List의 복사 (2): List.copyOf (0) | 2023.03.01 |
---|---|
Java - List의 복사 (1): Collections.unmodifiableList (2) | 2023.03.01 |
Java - Iterator (0) | 2022.11.29 |
Java - Collections Class (0) | 2022.11.28 |
Java - Map과 HashMap (0) | 2022.11.24 |