귀찮지만 만들어보자

이펙티브 자바 - 메서드(2) 본문

이펙티브 자바

이펙티브 자바 - 메서드(2)

타우렌주술사 2019. 1. 27. 02:22

적시에 방어적 복사본을 만들라


자바로 작성한 클래스는 시스템의 다른 부분에서 무슨짓을 하든 그 불변식이 지켜진다.
하지만 다른 클래스로부터의 침범을 아무런 노력없이 막을 수 있는 건 아니다.
클라이언트가 불변식을 깨뜨리려고 혈안이 되어있다고 가정하고 방어적으로 프로그래밍해야한다

그니까 요점은 생성된 객체 내부의 값을 변조할 수 없게 코딩해야한다는 말이다.

Date를 매개변수로 받는 경우를 생각해보면, Date는 가변이기 때문에 어렵지 않게 불변식을 깨뜨릴 수 있다.
자바8에 추가된 Instant나 LocalDateTime 등을 사용하면 이런 점을 방지할 수 있다.
얘네들은 불변이기 때문에 생각해보니 우리 프로젝트는 아직 Date를 사용한다
또 다른 방법으로는 매개변수를 그대로 사용하지 않고, 생성자에서 값을 복사해서 사용하는 것이 있다.
이렇게 하면 가변 매개변수에 접근해서 값을 변조하는 방법은 통하지 않는다.

public Period(Date start, Date end) {
  this.start = new Date(start.getTime());
  this.end = new Date(end.getTime());
}

여기서 Date의 clone을 사용하지 않았다.
Date는 final이 아니므로 clone이 Date가 정의한게 아닐 수 있다.
그래서 내부에서 새로운 객체를 생성하고 값을 입력하는 방식을 사용하고 있다.
매개변수가 제3자에 의해 확장될 수 있는 타입이라면 방어적 복사본을 만들 때 clone을 사용해선 안된다.
쉽게 말하면 Date를 상속받아서 이상한짓(?)을 한게 매개변수로 들어올 경우를 대비하라는 것이다.

Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
p.end().setYear(78); // 이렇게 아직 변경이 가능하다 -_-..

아직 이런식으로 변경이 가능하기 때문에 가변 필드에 방어적 복사본을 반환한다.
public Date start() {
  return new Date(start.getTime());
}

생성자에서 복사할때와 다른점은 clone을 사용해도 된다는 점이다.
가변인자로 불러오는 시점에서 이미 Date 객체인게 확실하기 때문이다.

이런 방어적 복사에는 성능 저하가 따르고 항상 쓸 수 있는 것도 아니다.
그러니까 그냥 불변 객체를 쓰도록하자 -_-;