Java ‐ 적시에 방어적 복사본을 만들라[Effective Java Item 50] - thought-corner/Backend-PlayGround GitHub Wiki

  • 클라이언트가 불변식을 깨뜨리려 혈안이 되어 있다고 가정하고 방어적으로 프로그래밍을 해야 한다.
// Bad
public final class Period {
    private final Date start;
    private final Date end;

   /**
    * @param start 시작 시각
    * @param end 종료 시각
    * @throws IllegalArgumentException 시작 시각이 종료 시각보다 늦을 때 발생한다.
    * @throws NullPointerException start 혹은 end가 null이면 발생한다.
    */
    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;
    }
}
  • 외부 공격으로부터 인스턴스 내부를 보호하려면 생성자에서 받은 가변 매개변수 각각을 방어적으로 복사해야 한다.
  • 매개변수 유효성을 검사하기 전에 방어적 복사본을 만들고 이 복사본으로 유효성을 검사한다.
public Period(Date start, Date end) {
    this.start = new Date(start.getTime());  // (1). 방어적 복사본을 만든다.
    this.end = new Date(end.getTime());

    if (start.compareTo(end) > 0) {          // (2). 유효성을 검증한다.
        throw new IllegalArgumentException(start + "가 " + end + "보다 늦다.");
    }
}
  • 그러나 한 가지 주의할 점은 방어적 복사에는 성능 저하가 따르고 항상 쓸 수 있다는 것이 아니라는 것을 명심해야 한다.