View

반응형

검사 예외를 잘 활용하면 프로그램의 안정성과 질을 높일 수 있다. 하지만 검사 예외를 과하게 사용하면 오히려 사용하기 불편한 API가 될 수 있다.

 

검사 예외와 비검사 예외 선택 기준

API를 제대로 사용해도 발생할 수 있는 예외 거나, 프로그래머가 의미 있는 조치를 취할 수 있는 경우라면 검사 예외를 그렇지 않다면 비검사 예외를 사용하자.

 

검사 예외 회피 방법 - 비검사 예외

아래의 코드는 API 사용자가 검사 예외를 처리하는 사례이다.

// 비검사 예외를 호출한다.
} catch (TheCheckedException e) { 
    throw new AssertionError();  
}

 

// 에러 스택 코드를 출력하고 시스템을 종료한다.
} catch (TheCheckedException e) {
    e.printStackTrace();
    System.exit(1);
}

과연 위와 같은 방식이 필요 했을까?

처음부터 비검사 예외로 만들었으면 더 좋았을 것이다.

 

검사 예외 회피 방법 - Optional

메서드가 단 하나의 검사 예외만 던질 때 API 사용자의 부담은 더욱 커진다. 단 하나의 검사 예외를 위해 try 블록을 추가해야 하고 스트림에서 메서드를 직접 사용하지 못하게 된다. 따라서 이런 상황이라면 검사 예외를 안던지는 방법을 고려해야 한다.

그중 가장 쉽게 검사 예외를 회피하는 방법이 Optional을 반환하는 것이다. 검사 예외를 던지는 대신 빈 옵셔널을 반환하면 된다. 다만, 예외가 발생한 이유에 대한 부가 정보를 담을 수 없다는 단점이 있다.

반면, 예외를 사용하면 구체적인 예외 타입이나 그 타입이 제공하는 메서드들을 활용해 부가 정보를 제공할 수 있다.

 

검사 예외 회피 방법 - 메서드 쪼개기

검사 예외를 던지는 메서드를 2개로 쪼개 비검사 예외로 바꿀 수 있다.

// before - 검사 예외를 던지는 메서드
try {
    Obj.action(args);    
} catch (TheCheckedException e) {
    // 예외 상황에 대처하는 로직
}

 

// after - 상태 검사 메서드와 비검사 예외를 던지는 메서드
if (obj.actionPermitted(args)) {
    obj.action(args);
} else {
    // 예외 상황에 대처하는 로직
}

 

이 리팩터링을 모든 상황에 적용할 수는 없지만, 적용할 수 있다면 더 쓰기 편한 API를 제공할 수 있다. 다만, 외부 동기화 없이 여러 스레드가 동시에 접근할 수 있거나 가변 상태라면 위와 같은 리팩터링은 적절하지 않다.

obj.actionPermitted() 메서드는 상태 검사 메서드에 해당하고 obj.action()을 호출하는 시점에 객체의 상태가 변할 수도 있기 때문이다.

만약 실패 시 스레드를 중단하길 원한다면 다음과 같이 작성해도 된다.

obj.action(args);

한 줄짜리 호출이 주로 쓰일 거로 생각되면 리팩터링을 하자.

 

핵심 정리

  • 꼭 필요한 곳에서만 검사 예외를 사용하자.
  • API 호출자가 예외 상황에서 복구할 방법이 없다면 비검사 예외를 던지자.
  • 복구가 가능하고 호출자가 처리해주길 바란다면 옵셔널 반환을 고려하자.
  • 옵셔널만으로 처리하기에 충분한 정보를 제공할 수 없을 때만 검사 예외를 던지자.
반응형
Share Link

인기 글

최신 글

전체 방문자

Today
Yesterday