객체에 값을 대입할 때, new 키워드를 사용하여 새로운 객체로 복사해주는 것을 의미한다.

public Cards(List<Card> cards) {
		this.cards = new ArrayList<>(cards);
}

이렇게 새로 객체를 생성할 경우, 내부 데이터 값만 복사되고 참조가 끊기게 되어 원본의 변경에 상관없이 초기 데이터를 안전하게 사용할 수 있다.

방어적 복사 시점

카드를 관리하는 도메인인 Cards 에서 카드가 1개 이상임이 보장되어야 하여 유효성 검사를 한다고 가정하자.

public Cards(List<Card> cards) {
if(validation(cards)) {
		throw new IllegalArgumentException("카드는 한장 이상이어야합니다.");
}
this.cards = new ArrayList<>(cards);
}

보통은 이렇게 검증 후 할당을 하고 있을 것이다.

그러나 멀티 스레딩 환경일 때는 원본 값이 변경 될 위험이 크기 때문에 할당 후 할당한 값에 대해서 검증을 해주는 것이 더욱 안정적인 객체를 만들 수 있다.

public Cards(List<Card> cards) {
this.cards = new ArrayList<>(cards);

if(validation(this.cards)) {
		throw new IllegalArgumentException("카드는 한장 이상이어야합니다.");
}
}

원본 훼손을 방지하기 위해

생성자에서 복사본을 만든 것은 원본과의 참조를 끊기 위해서였다.

이번에는 getter 를 통해 나간 객체에 대해서도 방어적 복사를 통해 현재 객체의 훼손을 방어를 해보자.

public List<Card> getCards (){
	return new ArrayList<>(cards);
}

참고