item 75 : 예외의 상세 메시지에 실패 관련 정보를 담으라
Last updated
Was this helpful?
Last updated
Was this helpful?
예외를 제대로 처리하지 못하면 프로그램은 실패하며, 자바 시스템은 스택 추적 정보를 자동으로 출력한다. 이 정보는 예외의 클래스 이름, 상세 메시지, 그리고 스택 추적 경로를 포함한다.
스택 추적
은 예외 객체의 toString 메 서드를 호출해 얻는 문자열로, 보통은 예외의 클래스 이름 뒤에 상세 메시지 가 붙는 형태다. 스택 추적은 문제를 분석하는 프로그래머와 사이트 신뢰성 엔지니어(Site Reliability Engineer, SRE)가 사용할 수 있는 유일한 정보인 경우가 많다.
특히, 실패를 재현하기 어려운 경우라면 스택 추적이 더욱 중요하다. 따라서 실패 원인에 관한 정보를 가능한 한 많이 상세 메시지에 담아야 한다.
필요한 모든 정보 제공: 발생한 예외와 관련된 모든 매개변수와 필드 값을 메시지에 담아야 한다.
예컨대 IndexOutOfBoundsException의 상세 메 시지는 범위의 최솟값과 최댓값, 그리고 그 범위를 벗어났다는 인덱스의 값 을 담아야 한다. 이 정보는 실패에 관한 많은 것을 알려준다.
구체적이고 간결하게: 장황하게 작성하기보다는 문제를 명확히 설명할 수 있는 핵심 정보를 담아야 한다.
보안 정보 제외: 암호, 키 등 민감한 정보는 메시지에 포함되지 않아야 한다.
관련 데이터를 모두 담아야 하지만 장황할 필요는 없다. 문제를 분석하는 사람 은 스택 추적뿐 아니라 관련 문서와 (필요하다면) 소스코드를 함께 살펴본다.
예외의 상세 메시지와 최종 사용자에게 보여줄 오류 메시지를 혼동해서는 안 된다. 최종 사용자
에게는 친절한 안내 메시지를 보여줘야 하는 반면, 예외 메시지
는 가독성보다는 담긴 내용이 훨씬 중요하다
실패를 포착하는 상세 메시지
예외를 던질 때, 실패와 관련된 정보를 최대한 상세히 기록하여 메시지를 포함해야 한다.
실패 정보를 명확히 드러내면, 디버깅 및 문제 해결이 쉬워진다.
예를 들어, IndexOutOfBoundsException
의 생성자에서 아래와 같이 상세 정보를 추가하는 설계가 권장된다:
상세 메시지 포함: String.format
을 사용하여 최솟값, 최댓값, 인덱스 값을 포함한 상세 메시지를 생성
접근자 메서드 제공: getLowerBound
, getUpperBound
, getIndex
메서드를 통해 각 정보를 안전하게 가져올 수 있다.
사용 예시:
1. 예외 메시지의 중요성
목적: 발생한 문제를 최대한 빠르고 명확하게 파악할 수 있어야 한다.
문제 상황: 아래와 같은 단순 메시지는 유용성이 떨어진다.
이런 경우, "무엇이", "어디서", "왜" 문제가 발생했는지를 알기 어렵다.
권장 방식: 상세한 정보를 제공하여 디버깅 시간을 줄이고 문제의 원인을 명확히 전달한다.
2. 실패 정보를 저장하고 접근 가능하게 설계
예외 객체 내부에 실패 정보를 저장하면 프로그램에서 이를 활용할 수 있다.
예를 들어, lowerBound
, upperBound
, index
값을 확인하여 잘못된 입력 값을 사용자에게 안내할 수 있다.
비교 예시:
실패 정보 저장 없음
실패 정보 저장 및 활용 가능
3. API 설계와 일관성
Java 라이브러리의 일부 예외 클래스는 상세 정보를 전달하지 않는 단순한 설계를 채택했지만, 상세 정보를 포함한 설계는 유지보수성과 디버깅 편의성 측면에서 장점이 크다.
따라서, 애플리케이션 수준에서 예외를 설계할 때는 추가적인 정보와 접근자 메서드를 제공하는 것이 유리하다.
4. 검사 예외와 비검사 예외의 차이
검사 예외(Checked Exception):
메서드 시그니처에 선언되며, 호출하는 쪽에서 반드시 처리해야 한다.
실패 정보를 저장하고, 복구 작업을 돕는 접근자 메서드가 특히 유용하다.
비검사 예외(Unchecked Exception):
런타임에 발생하며, 반드시 처리하지 않아도 된다.
프로그램적 접근이 드물지만, toString
을 통해 디버깅 정보를 제공하는 것이 좋다.
실패 정보를 포착하는 상세 메시지를 예외 객체 생성 시 포함하라.
예외 객체에 실패 정보를 저장하고, 이를 접근할 수 있는 메서드를 제공하라.
toString
이나 로그 메시지에 유용한 정보를 포함시켜 디버깅 시간을 줄여라.
검사 예외와 비검사 예외의 특성을 고려하여 설계하라.
스택 추적 정보를 많은 사람이 볼 수 있으므로, 비밀번호나 암호 키 같은 정보는 포함해서는 안된다.
예외 메시지: 디버깅을 위한 정보로 작성됩니다. 가독성보다는 내용의 정확성이 중요하다.
사용자 메시지: 사용자에게 보여줄 메시지는 친절하게 작성하고, 현지어로 번역될 수 있어야 한다.
실패 상황에 필요한 정보를 예외 생성자에서 모두 받아 상세 메시지로 포함하면, 문제를 분석하는 데 큰 도움이 된다.
개선된 IndexOutOfBoundsException 생성자 예시
실패 정보를 객체 내부에 저장
예외 객체 내부에 실패 정보를 저장해두면, 프로그램에서 추가적인 분석이나 복구 작업에 활용할 수 있다.
예를 들어, 실패 정보를 저장하기 위해 lowerBound
, upperBound
, index
와 같은 필드를 예외 객체에 포함할 수 있다.
접근자 메서드 제공
저장한 실패 정보에 접근할 수 있도록 접근자 메서드(getter)를 제공하자.
예:
특히, 검사 예외(Checked Exception)의 경우, 실패 정보를 복구하는 데 유용하다.
toString 메서드 활용
toString
메서드가 반환하는 값에 상세 정보를 포함시키면 디버깅 시 유용하다.
비검사 예외(Unchecked Exception)의 경우에도 접근자 메서드를 제공하는 것이 좋다.
포괄적 정보 제공: 실패 원인을 정확히 기술하여 문제를 빠르게 파악할 수 있다.
반복 코드 방지: 예외 클래스로 메시지 생성 로직을 캡슐화하여 중복 작업을 줄인다.
예외 연쇄는 저수준 예외(근본 원인)를 고수준 예외에 포함시키는 방식이다. 이를 통해 문제의 근본 원인을 분석할 수 있다.
원인 추적 가능: getCause()
메서드를 통해 근본 원인을 확인할 수 있다.
스택 추적 통합: 상위 예외와 하위 예외의 정보를 모두 스택 추적에 포함한다.
목적: 발생한 문제를 최대한 빠르고 명확하게 파악할 수 있어야 한다.
문제 상황: 아래와 같은 단순 메시지는 유용성이 떨어진다.
이런 경우, "무엇이", "어디서", "왜" 문제가 발생했는지를 알기 어렵다.
권장 방식: 상세한 정보를 제공하여 디버깅 시간을 줄이고 문제의 원인을 명확히 전달한다.
예외 객체 내부에 실패 정보를 저장하면 프로그램에서 이를 활용할 수 있다.
예를 들어, lowerBound
, upperBound
, index
값을 확인하여 잘못된 입력 값을 사용자에게 안내할 수 있다.
비교 예시:
실패 정보 저장 없음
실패 정보 저장 및 활용 가능
Java 라이브러리의 일부 예외 클래스는 상세 정보를 전달하지 않는 단순한 설계를 채택했지만, 상세 정보를 포함한 설계는 유지보수성과 디버깅 편의성 측면에서 장점이 크다.
따라서, 애플리케이션 수준에서 예외를 설계할 때는 추가적인 정보와 접근자 메서드를 제공하는 것이 유리하다.
검사 예외(Checked Exception):
메서드 시그니처에 선언되며, 호출하는 쪽에서 반드시 처리해야 한다.
실패 정보를 저장하고, 복구 작업을 돕는 접근자 메서드가 특히 유용하다.
비검사 예외(Unchecked Exception):
런타임에 발생하며, 반드시 처리하지 않아도 된다.
프로그램적 접근이 드물지만, toString
을 통해 디버깅 정보를 제공하는 것이 좋다.
예외 메시지는 실패 원인을 분석하는 데 중요한 정보를 제공하자
모든 매개변수와 상태 정보를 담아 예외 생성자를 설계하자
필요시 예외 연쇄를 활용해 문제의 근본 원인을 제공하자
사용자 메시지와 예외 메시지를 명확히 구분하여 설계하지
적절한 예외 메시지와 실패 포착은 디버깅과 시스템 신뢰성을 높이는 데 핵심