Open
Description
Discussed in https://github.com/orgs/Study-2-Effective-Java/discussions/179
Originally posted by JoisFe March 26, 2023
아이템 75. 예외의 상세 메시지에 실패 관련 정보를 담으라
스택 추적 (Stack Trace)
- 예외를 잡지 못해 프로그램이 실패하면 자바 시스템은 그 예외의 스택 추적 정보를 자동으로 출력
- 스택 추적은 예외 객체의 toString 메서드를 호출해 얻는 문자열 (보통은 예외의 클래스 이름 뒤에 상세 메시지가 붙는 형태)
- 해당 정보가 실패 원인을 분석해야 하는 프로그래머 혹은 SRE (Site Reliability Engineer, SRE)가 얻을 수 있는 유일한 정보인 경우가 많음
- 또한 실패를 재현하기 어렵다면 더 자세한 정보를 얻기 어렵거나 불가능함
예외의 toString 메서드에 실패 원인에 관한 정보를 가능한 많이 담아 반환하는 일은 매우 중요
- 사후 분석을 위해 실패 순간의 상황을 정확히 포착해 예외의 상세 메시지에 담아야 함!
예외의 상세 메시지를 작성하는 방법
실패 순간을 포착하려면 발생한 예외에 관련된 모든 매개변수와 필드의 값을 실패 메시지에 담아야 함
- EX) IndexOutOfBoundsException의 상세 메시지는 범위의 최솟값과 최댓값, 그리고 그 범위를 벗어났다는 인덱스의 값을 담아야 함
- (해당 정보는 실패에 관한 많은 것을 알려줌)
- 셋 중 한두 개 혹은 셋 모두가 잘못됐을 수 있기 때문
- 이상의 현상들은 모두 원인이 다르므로 현상을 보면 무엇을 고쳐야 할지를 분석하는데 도움이 됨
- 관련 데이터를 모두 담아야 하지만 장황할 필요는 없음 (문제를 분석하는 사람은 스택 추척뿐만 아니라 관련 문서, 소스코드를 함께 살펴보기 때문)
예외의 상세 메시지와 최종 사용자에게 보여줄 오류 메시지를 혼동해선 안됨
- 최종 사용자에게는 친절한 안내 메시지를 보여줘야 함
- 반면 예외 메시지는 가독성 보단 담긴 내용이 훨씬 중요
- 예외 메시지의 주 소비층은 문제를 분석해야 할 프로그래머와 SRE 엔지니어 이기 때문
실패를 적절히 포착하려면 필요한 정보를 예외 생성자에서 모두 받아서 상세 메시지까지 미리 생성해놓는 방법 또한 괜찮음
- EX) 현재의 IndexOutOfBoundsException 생성자는 String을 받지만 아래의 예시 코드와 같이 구현해도 좋음
/**
* 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에 드디어 정수 인덱스 값을 받는 생성자가 추가되었음
- 하지만 아쉽게도 최솟값과 최댓값까지 받지는 않음
- 이처럼 자바 라이브러리에서 이 조언을 적극 수용하진 않았지만 위 같은 코드처럼 권장함!
- 이렇게 하면 프로그래머가 던지는 예외는 자연스럽게 실패를 더 잘 포착함
- 또한 고품질의 상세 메시지를 만들어내는 코드를 예외 클래스 안으로 모아주는 효과가 있음
- 따라서 클래스 사용자가 메시지를 만드는 작업을 중복하지 않아도 됨
예외는 실패와 관련한 정보를 얻을 수 있는 접근자 메서드를 적절히 제공하는 것이 좋음
- 위 내용은 아이템 70. 복구할 수 있는 상황에는 검사 예외를, 프로그래밍 오류에는 런타임 예외를 사용하라 #164 참고
- 앞의 예시 코드를 예로 들면 lowerBound, upperBound, index 정도가 적당
- 포착한 실패 정보는 예외 상황을 복구하는 데 유용할 수 있으므로 접근자 메서드는 비검사 예외보다는 검사 예외에서 더 빛을 발함
- 비검사 예외의 상세 정보에 프로그램적으로 접근하길 원하는 프로그래머는 드물 것이지만 (전혀 없지는 않음)
- 하지만
toString이 반환한 값에 포함된 정보를 얻어올 수 있는 API를 제공하자
일반 원칙을 따른다는 관점에서는 비검사 예외에도 상세 정보를 알려주는 접근자 메서드를 제공하는 것을 권함!
Metadata
Metadata
Assignees
Labels
No labels