티스토리 뷰
메서드와 생성자 대부분은 입력 매개변수 값이 특정 조건을 만족하길 바란다.
이런 제약은 반드시 문서화하고 메서드 몸체가 시작되기 전에 검사해야한다.
오류는 가능한 빨리 잡아야한다.
매개변수 검사를 제대로 하지 못했을 시 문제점
실패 원자성(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} ≤ 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를 어디서 가져왔는지 추적하기 어려워 디버깅이 괴로워진다.
- 생성자의 매개변수 유효성 검사는 클래스 불변식을 어기는 객체가 만들어지지 않게 하는데 꼭 필요
- 유효성 검사에도 예외가 있음
- 검사 비용이 너무 높거나 실용적이지 않을때
- 계산 과정에서 암묵적으로 검사가 수행될 때 → 암묵적 유효성 검사에 너무 의존하면 실패 원자성을 해칠 수 있음
- 매개변수에 제약을 두는게 무조건 좋다는게 아니다. 메서드는 최대한 범용적으로 설계해야함 → 건네받은 값으로 제대로된 일을 한다면 제약은 적을수록 좋음
결론
메서드나 생성자를 작성할때면 그 매개변수들에 어떤 제약이 있을지 생각해야함
제약들을 문서화하고 메서드 시작 부분에서 유효성 검사를 하자. → 오류는 최대한 빨리 발생한 곳에서 잡는 것이 좋다.
'Java > Effective Java' 카테고리의 다른 글
[Effective Java] 51.메서드 시그니처를 신중히 설계하라 (0) | 2022.04.04 |
---|---|
[Effective Java] 50.적시에 방어적 복사본을 만들라 (0) | 2022.04.04 |
[Effective Java] 48. 스트림 병렬화는 주의해서 적용하라 (0) | 2022.04.01 |
[Effective Java] 47. 반환 타입으로는 스트림보다 컬렉션이 낫다 (0) | 2022.04.01 |
[Effective Java] 46. 스트림에서는 부작용 없는 함수를 사용하라 (0) | 2022.04.01 |