50. 적시에 방어적 복사본을 만들라
자바는 안전한 언어?
자바는 C, C++ 같은 네이티브 언어와 다르게 JVM에 의해 관리 받는 메모리를 사용하기 때문에 버퍼 오버런, 배열 오버런, 와일드 포인터 같은 메모리 오류에서 안전하다.
자바는 클래스의 객체지향 특성을 통해 클래스 내부를 불변하게 유지할 수 있는 강점이 있다. 하지만 그런 클래스의 불변식을 클라이언트가 깨뜨린다고 가정하고 방어적인 프로그래밍을 해야 한다.
사례: Period 클래스
기간을 표현하는 클래스 - 불변식을 지키지 못함
public final class Period {
private final Date start;
private final Date end;
public Period(Date start, Date end) {
if (start.compareTo(end) > 0)
throw new IllegalArgumentException(
start + "가 " + end + "보다 늦다.");
this.start = start;
this.end = end;
}
public Date start() {
return start;
}
public Date end() {
return end;
}
... // 나머지 코드 생략
}Data가 가변이라는 사실을 이용하여 Period 인스턴스의 내부를 공격
자바 8 이후로는 Date 대신 Instant class를 사용하면 된다. 혹은 LocalDateTime이나 ZonedDateTime을 사용해도 된다.
Date는 오래된 API이라 더 이상 사용하면 안된다. 하지만 어쩔수 없이 사용해야 하는 상황에서는 방어적 복사(defensive copy) 를 해야 한다.
해결법: 방어적 복사
방어적 복사본이 비효율적일수 있기 때문에 되도록 불변 객체들을 조합하여 객체를 구성해서 방어적 복사를 할 일이 줄여야 한다.
호출자가 컴포넌트 내부를 수정하지 않는다는 확신이 있다면 방어적 복사를 생략할수 있지만 매개변수나 반환값을 수정하지 말아야 함을 문서화해야 한다.
정리
클래스가 클라이언트로부터 받는 혹은 클라이언트로 반환하는 구성요소가 가변이라면 그 요소는 반드시 방어적으로 복사해야함.
복사 비용이 너무 크거나 잘못 수정할 일이 없음을 신뢰한다면 구성 요소 수정에 대한 책임 내용을 문서에 명시해야함.
Last updated