DEV ℧ Developer Diary

[EffectiveJava] item75 - 예외의 상세 메시지에 실패 관련 정보를 담으라

예외를 잡지 못해 프로그램이 실패하면 자바 시스템은 그 예외의 스택 추적(stack trace) 정보를 자동으로 출력한다.

스택 추척은 예외 객체의 toString 메서드를 호출해 얻는 문자열로, 보통은 예외의 클래스 이름 뒤에 상세 메시지가 붙는 형태다.

실패 정보가 필요한 이유?

이 정보가 실패 원인을 분석해야 하는 프로그래머 혹은 사이트 신뢰성 엔지니어 (site reliability engineer, SRE)가 얻을 수 있는 유일한 정보인 경우가 많다.

더구나 그 실패를 재현하기 어렵다면 더 자세한 정보를 얻기가 어렵거나 불가능 하다.

주요 실패 정보

실패 순간을 포착하려면 발생한 예외에 관여된 모든 매개변수와 필드의 값을 실패 메시지에 담아야 한다.

예를들면 IndexOutOfBoundsException의 상세 메시지는 범위의 최솟값과 최댓값, 그리고 그 범위를 벗어났다는 인덱스의 값을 담아야 한다. 이 정보는 실패에 관한 많은 것을 알려준다.

필요 없는 실패 정보

관련 데이터를 모두 담아야 하지만 장황할 필요는 없다.

스택 추적에는 예외가 발생한 파일 이름과 줄번호는 물론 스택에서 호출한 다른 메서드들의 파일 이름과 줄번호까지 정확히 기록되어 있는 게 보통이다.
그러니 문서와 소스코드에서 얻을 수 있는 정보는 길게 늘어놔봐야 군더더기가 될 뿐이다.

최종 사용자에게 보여줄 오류 메시지

예외의 상세 메시지와 최종 사용자에게 보여줄 오류 메시지를 혼동해서는 안된다.

최종 사용자에게는 친절한 안내 메시지를 보여줘야 하는 반면, 에외 메시지는 가독성보다는 담긴 내용이 훨씬 중요하다.

예외 메시지는 가독성보다는 담긴 내용이 훨씬 중요하다. 예외 메시지의 주 소비층은 문제를 분석해야 할 프로그래머와 SRE 엔지니어이기 때문이다.

예외 생성자

실패를 적절히 포착하려면 필요한 정보를 예외 생성자에서 모두 받아서 상세 메시지까지 미리 생성해놓는 방법도 괜찮다.

IndexOutOfBoundsException 예외 생성자

/**
 * IndexOutOfBoundsException을 생성한다.
 *
 * @param lowerBound 인덱스의 최소값
 * @param upperBound 인덱스의 최댓값 + 1
 * @param index 인덱스의 실제값
 */
public IndexOutOfBoundsException(int lowerBound, int upperBound, int index) {
    /* 실패를 포착하는 상세 메시지를 생성한다. */
    super(String.format("최솟값: %d, 최댓값: %d, 인덱스:%d", lowerBound, upperBound, index));

    /* 프로그램에서 이용할 수 있도록 실패 정보를 저장해둔다. */
    this.lowerBound = lowerBound;
    this.upperBound = upperBound;
    this.index = index;
}

자바 9에서는 IndexOutOfBoundsException에 드디어 정수 인덱스 값을 받는 생성자가 추가되었다.

하지만 아쉽게도 최솟값과 최댓값까지 받지는 않는다. 이처럼 자바 라이브러리에서는 이조언을 적극 수용하지는 않지만, 이책의 저자는 강력히 권장하고 있다.

예외 접근자 메서드

예외는 실패와 관련한 정보를 얻을 수 있는 접근자 메서드를 적절히 제공하는 것이 좋다.
포착한 실패 정보는 예외 상황을 복구하는 데 유용할 수 있으므로 접근자 메서드는 비검사 예외보다는 검사 예외에서 더 빛을 발한다.