티스토리 뷰

반응형

메서드와 생성자 대부분은 입력 매개변수 값이 특정 조건을 만족하길 바란다.

이런 제약은 반드시 문서화하고 메서드 몸체가 시작되기 전에 검사해야한다.

오류는 가능한 빨리 잡아야한다.

 

 

매개변수 검사를 제대로 하지 못했을 시 문제점

실패 원자성(failure atomicity)을 어기는 결과 초래 : 메서드 수행 중간에 모호한 예외를 던지며 실패하거나 잘 수행되더라도 잘못된 결과를 반환할 수 있다.

실패 원자성 : 호출된 메서드가 실패하더라도 해당 객체는 호출 전의 상태를 유지해야한다.

 

 

매개변수 제약을 어길 시 발생하는 예외 문서화

public이나 protected 메서드는 매개변수 값이 잘못됐을 때 던지는 예외를 문서화해야한다. (@throws 자바독 태그 사용)

보통 IllegalArgumentExcepiton, IndexOutOfBoundsException, NullPointerException 중 하나다.

문서화함으로써 사용자가 제약을 지킬 가능성을 높일 수 있다.

/**
 * Returns a BigInteger whose value is {@code (this mod m}).  This method
 * differs from {@code remainder} in that it always returns a
 * <i>non-negative</i> BigInteger.
 *
 * @param  m the modulus.
 * @return {@code this mod m}
 * @throws ArithmeticException {@code m} &le; 0
 * @see    #remainder
 */
public BigInteger mod(BigInteger m) {
    if (m.signum <= 0)
        throw new ArithmeticException("BigInteger: modulus not positive");

    BigInteger result = this.remainder(m);
    return (result.signum >= 0 ? result : result.add(m));
}

위 메서드는 m이 null이면 NullPointerException 을 던지는데도 불구하고 메서드 설명에 그런 말이 없다.

그 이유는 이 설명을 BigInteger 클래스 수준에서 기술했기 때문이다.

클래스 수준 주석을 통해 그 클래스의 모든 public 메서드에 적용할 수 있어서 더 깔끔한 방법이다.

 

매개변수의 유효성 검사

1) java.util.Objects.requireNonNull

자바 7에 추가된 java.util.Objects.requireNonNull 메서드를 이용하면 편하게 null 검사를 수동으로 하지 않아도된다.

(원하는 예외 메시지도 지정 가능)

public static <T> T requireNonNull(T obj) {
    if (obj == null)
        throw new NullPointerException();
    return obj;
}
this.strategy = Objects.requireNonNull(strategy, "전략");

 

2) assert

공개되지 않은 메서드라면 패키지 제작자인 사람이 메서드가 호출되는 상황을 통제할 수 있다.

public이 아닌 메서드라면 단언문(assert)를 사용하여 매개변수 유효성을 검증할 수 있다.

//재귀 정렬용 private 도우미 함수
private static void sort(long a[],int offset, int length) {
    assert a != null;
    assert offset >= 0 && offset <= a.length;
    assert length >= 0 && length <= a.length - offset;
    //생략..
}
  • assert 문은 실패하면 AssertionError를 던짐
  • 런타임에 아무런 효과도, 아무런 성능 저하도 없다.

 

3) 나중에 쓰려고 저장하는 매개변수의 유효성을 검사해라

  • 메서드가 직접 사용하진 않으나 나중에 쓰기위해 저장하는 매개변수는 더 신경써서 검사해야함
  • 입력받은 int 배열의 List를 반환하는 메서드가 requireNonNull을 이용해 null 검사를 한다면?
    클라이언트가 이 메서드에 null을 건네면 NullPointerException을 던질 것이다.
  • 그런데, 이 검사를 생략한다면? 이 메서드는 새로 생성한 List 인스턴스를 반환하게 되고 클라이언트가 그 List를 사용하려할때 그때가 되어서야 NullPointerException이 발생하게된다. 이 때는 List를 어디서 가져왔는지 추적하기 어려워 디버깅이 괴로워진다.
  • 생성자의 매개변수 유효성 검사는 클래스 불변식을 어기는 객체가 만들어지지 않게 하는데 꼭 필요
  • 유효성 검사에도 예외가 있음
    • 검사 비용이 너무 높거나 실용적이지 않을때
    • 계산 과정에서 암묵적으로 검사가 수행될 때 → 암묵적 유효성 검사에 너무 의존하면 실패 원자성을 해칠 수 있음
  • 매개변수에 제약을 두는게 무조건 좋다는게 아니다. 메서드는 최대한 범용적으로 설계해야함 → 건네받은 값으로 제대로된 일을 한다면 제약은 적을수록 좋음

 

결론

메서드나 생성자를 작성할때면 그 매개변수들에 어떤 제약이 있을지 생각해야함

제약들을 문서화하고 메서드 시작 부분에서 유효성 검사를 하자. → 오류는 최대한 빨리 발생한 곳에서 잡는 것이 좋다.

반응형
댓글
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday