규칙 57 예외는 예외적 상황에만 사용하라
- 이름이 말하듯이, 예의는 예의적인 상황에만 사용해야 한다. 평상시 제어 흐름(ordinary control flow)에 이용해서는 안 된다.
- 설계된 API는 클라이언트에게 평상시 제어 흐름의 일부로 예의를 사용하도록 강요해서는 안 된다.
- 특정한 예측 불가능 조건이 만족될 때만 호출할 수 있는 “상태 종속적(state-dependent)” 메서드를 가진 클래스에는 보통 해당 메서드를 호출해도 되는지를 알기 위한 “상태 검사(state一testing)” 메서드가 별도로 갖춰져 있다.
- 부적절한 상태의 객체에 상태 종속적 메서드를 호출하면 null 같은 특이값(distinguished value)이 반환되도록 구현하는 방법도 있다.
- 상태 검사 메서드와 특이값
- 외부적인 동기화 메커니즘 없이 병렬적으로 사용될 수 있는 객체거나, 외부적인 요인으로 상태 변화가 일어날 수 있는 객체라면 반드시 특이값 방식으로 구현해야 한다.
- 상태속적 메서드가 하는 일을 상태 검사 메서드가 중복해서 하는 바람에 성능이 어질까 우려된다면, 역시 특이값 방식을 따르는 것이 좋을 것이다.
- 다른 모든 조건이 동일하다면 상태 검사 메서드를 두는 편이 대체로 바람직하다.
규칙 58 복구 가능 상태에는 점검지정 예외를 사용하고, 프로그래밍 오류에는 실행시점 예외를 이용하라
- 자바는 세 가지 종류의 ‘throwable’을 제공한다. 점검지정 예외(checked exception), 실행시점 예외(runtime exception), 그리고 오류(error)다.
- 무점검(unchecked) ‘throwable’에는 실행시점 예외와 오류 두 가지가 있으며, 동작 방식은 같다.
- 둘 다 catch로 처리할 필요가 없으며, 일반적으로는 처리해서도 안 된다.
- 오류(error)는 JVM이 자원 부족(resource deficiency)이나 불변식 위반(invariant failure) 등, 더 이상 프로그램을 실행할 수 없는 상태에 도달했음을 알리기 위해 시용한다.
- 점검지정 예외는 메서드를 호출하면 해당 예외와 관계된 상황이 발생할 수 있음을 API 사용자에게 알리는 구실을 한다.
- 프로그래밍 오류를 표현할 때는 실행시점 예의를 사용하라.
- 사용자 정의 무점검 throwable은 RuntimeException의 하위 클래스로 만들어야 한다.
- 복구가 기능할 것 같으면 점검지정 예의를 사용하라. 아니라면 실행시점 예의를 이용하라.
규칙 59 불필요한 점검지정 예외 사용은 피하라
- 코드(code)를 반환하는 것과는 달리, 프로그래머로 하여금 예외적인 상황을 처리하도록 강제함으로써 안정성(reliability)을 높인다.
- 너무 남발하면 사용하기 불편한 API가 될수도 있다는 뜻이기도 하다.
규칙 60 표준 예외를 사용하라
- 자바 플랫폼 라이브러리에는 대부분의 API가 필요로 하는 기본적인 무점검 예외들이 갖추어져 있다.
- IllegalArgumentException : 잘못된 값을 인자로 전달했을 때 일반적으로 발생하는 예외다.
- IllegalStateException : 현재 객체 상태로는 호출할 수 없는 메서드를 호출했을 때 일반적으로 발생하는 예외다.
- NullPointException : null 인자를 받으면 되는 메서드에 nuU을 전달한 경우
- IndexOutOfBoundsException : 어떤 순서열(sequence)의 첨자를 나타내는 인자에 참조 기능 범위를 벗어난 값이 전달되었을 때
- UnsupportedOperationException : 어떤 객체가 호출된 메서드를 지원하지 않을 때 발생
규칙 61 추상화 수준에 맞는 예외를 던져라
- 상위 계층에서는 하위 계층에서 발생하는 예외를 반드시 받아서 상위 계층 추상화 수준에 맞는 예외로 바꿔서 던져야 한다.
- 아무 생각 없이 아래 계충에서 생긴 예의를 밖으로 전달하기만 하는 것보다야 예의 변환 기법이 낫지만, 남용하면 안 된다.
- 하위 계층에서 발생한 예제 정보가 상위 계층 예의를 발생시킨 문제를 디버깅하는 데 유용할 때 사용한다.
- 하위 계층 예의(원인cause)는 상위 계층 예외로 전달되는데, 상위 계층 예외에 있는 접근자 메서드(Throwable.getCause)를 호출하면 해당 정보를 꺼낼 수 있다.
규칙 62 메서드에서 던져지는 모든 예외에 대해 문서를 남겨라
- 점검지정 예의는 독립적으로 선언하고, 해당 예의가 발생하는 상황은 Javadoc @throws 태그를 사용해서 정확하게 밝혀라.
- Javadoc @throws 태그를 사용해서 메서드에서 발생 가능한 모든 무점검 예외에 대한 문서를 남겨라. 하지만 메서드 선언부의 throws 뒤에 무점검 예의를 나열하진 마라.
- 같은 이유로 동일한 예의를 던지는 메서드가 많다면, 메서드마다 문서를 만드는 대신, 해당 예외에 대한 문서는 클래스의 문서화 주석(documentation comment)에 남겨도 된다.
규칙 63 어떤 오류인지를 드러내는 정보를 상세한 메시지에 담으라
- 오류 정보를 포착해 내기 위해서는, 오류의 상세 메시지에 “예외에 관계된” 모든 인자와 필드의 값을 포함시켜야 한다.
규칙 64 실패 원자성 달성을 위해 노력하라
- 실패 원자성(failure atomicity) : 메서드 호출이 정상적으로 처리되지 못한 객체의 상태는, 메서드 호출 전 상태와 동일해야 한다.
- 변경 불가능 객체로 설계
- 인자 유효성(validity)을 검사
public Object pop()
if (size == 0)
throw new EmptyStackException();
Object result = elements[--size];
elementS[size] = null; //만기(obsolete) 참조 제거
return result;
}
- 연산 수행 도중에 발생하는 오류를 가로채는 복구 코드(recovery code)를 작성
- 객체의 임시 복사본상에서 필요한 연산을
- 실패 원자성은 일반적으로 권장되는 덕목이지만 언제나 달성할 수 있는 것은 아니다.
규칙 65 예외를 무시하지 마라
- 빈 catch 블록은 예의를 선언한 목적, 그러니까 예외적 상황을 반드시 처리하도록 강제한다는 목적에 배치된다.
- 적어도 catch 블록 안에는 예의를 무시해도 괜찮은 이유라도 주석으로 남겨 두어야 한다.