[Effective Java] 아이템 73 : 추상화 수준에 맞는 예외를 던지라

Loopy·2022년 12월 17일
0

이펙티브 자바

목록 보기
71/76
post-thumbnail

메서드가 저수준 예외를 처리하지 않고 바깥으로 전파( throws )해버릴 때, 수행하려는 일과 관련 없어 보이는 예외가 튀어나온다. 이는 내부 구현 방식을 드러내어 윗 레벨의 API를 오염시킬 수 있으므로 위험하다.

Spring

대표적인 예시로, 스프링에서도 데이터 계층에서 특정 DB에 종속되는 SQLException 과 같은 저수준 예외를, 예외 변환기 ( PersistenceExceptionTranslator) 를 통해 고수준 DataAccessException 으로 변환시킨다.

☁️ 예외 번역(Exception Translation)

이 문제를 피하려면, 상위 계층에서는 저수준 예외를 잡아 자신의 추상화 수준에 맞는 예외로 바꾸어 던져야 한다. 그리고 이를 예외 번역이라 한다.

try { 
	...
} catch (LowerLevelException e) {
	throw new HigherLevelException(...);
}

예외 번역을 사용한 예로 AbstractSequentialList 를 들어보자.

AbstractSequentialList

AbstractSequentialListList 인터페이스의 골격 구현(아이템 20)이다. 이 예에서 수행한 예외 번역은, List<E> 인터페이스의 get 메서드 명세에 명시된 필수사항이다.

/**
  이 리스트 안의 지정한 위치의 원소를 반환한다.
  @throws IndexOutOfBoundsException index가 범위 밖이라면, 
  즉 {@code index < 0 || index >= size()}이면 발생한다.
**/
public E get(int idex) {
   ListIterator<E> i = listIterator(index);
   try {
      return i.next();
   } catch (NoSuchElementException e) {
   	  throw new IndexOutOfBoundsException("인덱스: " + index);
   }
}

☁️ 예외 연쇄(Exception Chaining)

예외 연쇄란, 문제의 근본 원인인 저수준 예외를 고수준 예외에 실어 보내는 방식이다. 따라서 예외를 번역할 때, 저수준 예외가 디버깅에 도움이 된다면 예외 연쇄를 사용하도록 하자.

try { 
	...
} catch (LowerLevelException cause) {
    // 저수준 예외를 고수준 예외에 실어 보낸다.
	throw new HigherLevelException(cause);
}

대부분의 표준 예외는 아래와 같이 예외 연쇄용 생성자를 갖추고 있다.

class HigherLevelException extends Exception {
  	HigherLevelException(Throwable cause) {
  	   super(cause);
    }
}

문제의 원인을 getCause 메서드로 프로그램에서 접근할 수 있게 해주어, 원인과 고수준 예외의 스택 추적 정보를 잘 통합해준다.

☁️ 주의 사항

결론적으로 예외를 전파( throws )하는 것보다 예외 번역이 더 나은 방법이지만, 남용해서는 안된다. 우선순위는 다음과 같다.

  1. 가능하다면 저수준 메서드가 반드시 성공해 예외를 발생시키지 않도록 한다.
  2. 상위 계층 메서드의 매개변수 값을 아래로 넘기기 전에 미리 검사한다.
  3. 예외를 예방 및 처리 불가능할때 예외 번역을 사용한다.

만약 아래 계층에서의 예외가 불가피하다면, 상위 계층에서 예외를 조용이 처리하여 API 호출자에게까지 전파하지 않는 방법도 존재한다. 이 경우, 발생한 예외는 java.util.logging 같은 로깅 기능을 활용하여 기록해두자.

📚 핵심 정리
아래 계층의 예외를 예방하거나 스스로 처리할 수 없고, 상위 계층에 그대로 노출하기 곤란하다면 예외 번역을 사용하자. 이때 예외 연쇄를 이용하면 상위 계층에는 맥락에 어울리는 고수준 예외를 던지면서, 근본 원인도 함께 알려주어 오류를 분석하기에 좋다.

profile
개인용으로 공부하는 공간입니다. 잘못된 부분은 피드백 부탁드립니다!

0개의 댓글