핵심 정리: 방어적으로 프로그래밍하는 방법
- 불변 객체를 사용한다.
- 생성자에서 setup 이 된다면 참조만 가능하게 하자
- 가변 객체를 생성자나 메서드로 받는다면 매개변수를 방어적으로 복사하라.
- 매개변수가 제3자에 의해 확장될 수 있는 타입이라면 객체를 복사할 때 clone()을 사용하지 않는다.
- 접근자가 가변 필드를 제공할 때, 방어적 복사본을 반환한다.
- 접근자에서 방어적 복사본을 만들 때는 clone()을 사용해도 된다.
- 예외) - 방어적 복사본이 필요 없을 때
- 클라이언트가 객체를 수정하지 않을 것임을 확신하는 경우.
- 객체가 아니라 인스턴스의 경우
- 통제권을 넘기는 경우.
- 불변식이 깨지더라도 그 영향이 한정되는 경우
**- 가변 객체의 모습**
// 코드 50-1 기간을 표현하는 클래스 - 불변식을 지키지 못했다. (302-305쪽)
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 String toString() {
return start + " - " + end;
}
**- 방어적 복사본 생성**
//코드 50-3 수정한 생성자 - 매개변수의 방어적 복사본을 만든다. (304쪽)
public Period(Date start, Date end) {
this.start = new Date(start.getTime());
this.end = new Date(end.getTime());
if (this.start.compareTo(this.end) > 0)
throw new IllegalArgumentException(
this.start + "가 " + this.end + "보다 늦다.");
}
// 코드 50-5 수정한 접근자 - 필드의 방어적 복사본을 반환한다. (305쪽)
public Date start() {
**return new Date(start.getTime());**
}
public Date end() {
**return new Date(end.getTime());**
}
...