Reference/Effective-Java

[Effective-Java] Chapter10 #73. 추상화 수준에 맞는 예외를 던져라

나죽못고나강뿐 2023. 8. 1. 10:35
📌 예외 번역(Exception Translation)
💡 상위 계층에서는 저수준 예외를 잡아 자신의 추상화 수준에 맞는 예외로 바꿔 던져야 한다.
try {
    ... // 저수준 추상화를 이용한다.
} catch (LowerLevelException e) { 
    throw new HigherLevelException(...); // 추상화 수준에 맞게 번역한다.
}
  • 메서드가 저수준 예외를 처리하지 않고 바깥으로 전파하면, 내부 구현 방식을 드러내 윗 레벨 API를 오염시킨다.
  • 다음 릴리즈에서 구현 방식을 바꾸면 다른 예외가 튀어나와서 기존 Client 프로그램을 깨지게 할 수도 있다.

 

🟡 AbstractSequentialList

List 인터페이스
AbstractSequentialList 클래스

  • AbstractSequentialList는 List의 골격 구현(Item 20)이다.
  • 여기서 수행한 예외 번역은 List<E> 인터페이스의 get 메서드 명세에 명시된 필수 사항이다.

 

📌 예외 연쇄(Exception Chaining)
try {
    ... // 저수준 추상화 이용
} catch (LowerLevelException cause) {
    throw new HigherLevelException(cause); // 저수준 예외를 고수준 예외에 실어 보냄
}
  • 저수준 예외가 디버깅에 도움이 된다면 사용하라
  • 문제의 근본 원인(cause)인 저수준 예외를 고수준 예외에 실어 보내는 방식이다.
  • 필요하다면 별도의 접근자 메서드(Throwable의 getCause 메서드)를 통해 꺼내볼 수 있다.
  • 고수준 예외의 생성자는 상위 클래스 생성자에 원인을 넘겨, Throwable(Trowable) 생성자까지 건네지게 한다.

 

🟡 예외 연쇄용 생성자

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

  • 대부분의 표준 예외는 예외 연쇄용 생성자를 갖추고 있다. (없는 것도 있긴 하니 주의)
  • 그렇지 않은 예외도 Throwable의 initCause() 메서드로 '원인'을 직접 못박을 수도 있다.

 

class Foo {
    public static void main(String[] args) throws Exception
    {
        try {
            testException1();
        } catch (Throwable e) {
            // Cause : java.lang.ArrayIndexOutOfBoundsException
            System.out.println("Cause : " + e.getCause());
        }
    }
 
    public static void testException1() throws Exception
    {
        ArrayIndexOutOfBoundsException ae = new ArrayIndexOutOfBoundsException(); 
        Exception ioe = new Exception();
 
        ioe.initCause(ae);
        
        throw ioe;
    }
}

 

📌 주의 사항
💡 무턱대고 예외를 전파하는 것보다는 낫지만, 그렇다고 예외 번역을 남용하진 마라
  • 가능한 저수준 메서드가 반드시 성공하도록 하여, 예외 자체가 일어나지 않게 하는 것이 최선이다.
    • 상위 계층 메서드 매개변수 값을 아래 계측 메서드로 건네기 전에 미리 검사하는 방법도 있다.
  • 아래 계층의 예외를 피할 수 없다면 상위 계층에서 예외를 조용히 처리할 수도 있다.
    • 이 경우에는 적절한 Logging 기능을 활용해 기록해두면 좋다.
    • Client에 문제를 전파하지 않으면서, 프로그래머가 로그를 통해 추가 조치를 취할 수 있게 돕는다.