도당탕탕

Item75 : 예외의 상세 메시지에 실패 관련 정보를 담으라 본문

JAVA

Item75 : 예외의 상세 메시지에 실패 관련 정보를 담으라

backlo 2023. 2. 1. 13:39

자바에서 stack trace는 예외 객체의 toString 메서드를 호출해 출력한다. 보통 예외의 클래스 이름 뒤에 상세 메시지가 붙는 형태로 나타낸다. 이 정보를 통해 프로그래머 혹은 사이트 신뢰성 엔지니어가 실패 원인을 찾고 분석해 해결한다.

따라서 예외의 toString 메소드에 실패 원인에 관한 정보를 가능한 한 많이 담아 반환하는 일은 아주 중요하다. 그렇기 때문에 실패 순간을 포착하려면 발생한 예외에 관여된 모든 매개변수와 필드의 값을 실패 메시지에 담아야 한다.

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

  1. 인덱스가 최솟값보다 1만큼 작다. 혹은 0보다 작다.
  2. 인덱스가 최댓값하고 같다. 혹은 범위를 벗어났다.
  3. 인덱스의 최솟값과 최댓값이 같을 수도 있다.

이러한 현상 때문에 모든 원인이 다르므로, 이렇게 자세히 작성하면 무엇을 고쳐야 할지를 분석하는데 큰 도움이 된다.

그리고 관련 데이터를 모두 담아야 하지만, 장황할 필요는 없다. 문제를 분석하는 사람은 스택 추적뿐 아니라 관련 문서와 소스 코드를 함께 살펴본다. 즉 예외의 상세 메시지와 최종 사용자에게 보여줄 오류 메시지를 혼동해서는 안 된다. 최종 사용자에게 친절한 안내 메시지를 보여줘야 하는 반면, 예외 메시지는 가독성보다는 담긴 내용이 훨씬 중요하다.

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

  • IndexOutOfBoundsExceptions 클래스
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에서는 정수 인덱스를 받는 생성자가 추가되었지만, 아쉽게도 최솟값, 최댓값까지 받지는 않는다. 이처럼 자바 라이브러리에서는 이 조언을 적극 수용하지 않지만, 이펙티브 자바에서는 적극적으로 권장한다. 이렇게 해두면 프로그래머가 던지는 예외는 자연스럽게 실패를 더 잘 포착하기 때문이다.

예외는 실패와 관련한 정보를 얻을 수 있는 접근자 메소드를 적절히 제공하는 것이 좋다. 포착한 실패 정보는 예외 상황을 복구하는 데 유용할 수 있으므로 접근자 메서드는 비검사 예외보다는 검사 예외에서 더 빛을 발한다. 하지만 toString이 반환한 값에 포함된 정보를 얻어올 수 있는 API를 제공하자 하는 일반 원칙을 따른다는 관점에서, 비검사 예외라도 상세 정보를 알려주는 접근자 메소드를 제공하는 것을 권한다.

public boolean isTest() {
    boolean flag = true;
    flag = ....;

    if (flag) {
        return true;
    }

    return false;
}

public String errorMessage() {
    return "a = ...";
}
Comments