본문 바로가기

독서찰기(讀書札記)/이펙티브 자바

[아이템 71] 필요 없는 검사 예외 사용은 피하라

[배경]

검사 예외를 제대로 활용하면 API와 프로그램의 질을 높일 수 있다.

  • 결과를 코드로 반환하거나 비검사 예외를 던지는 것과 달리, 검사 예외는 문제를 프로그래머가 처리하여 안전성을 높이게끔 해준다.

 

[Why]

검사 예외를 과하게 사용하면 쓰기 불편한 API가 된다.

  • 어떤 메서드가 검사 예외를 던질 수 있다고 선언됐다면, 이를 호출하는 코드에서는 catch 블록을 두어 그 예외를 붙잡아 처리하거나 더 바깥으로 던져 문제를 전파해야만 한다.
  • 더구나 검사 예외를 던지는 메서드는 스트림 안에서 직접 사용할 수 없기 때문에 자바 8부터는 부담이 더욱 커졌다.

검사 예외가 프로그래머에게 지우는 부담은 메서드가 단 하나의 검사 예외만 던질 때가 특히 크다.

  • 이미 다른 검사 예외도 던지는 상황에서 또 다른 검사 예외를 추가하는 경우라면 기껏해야 catch 문 하나 추가하는 선에서 끝이다.
  • 검사 예외가 단 하나뿐이라면 오직 그 예외 때문에 API 사용자는 try 블록을 추가해야 하고 스트림에서 직접 사용하지 못하게 된다.

 

[How]

API를 제대로 사용해도 발생할 수 있는 예외이거나, 프로그래머가 의미 있는 조치를 취할 수 있는 경우라면 검사 예외를 사용할 수 있을 것이다. 하지만 둘 중 어디에도 해당하지 않는다면 비검사 예외를 사용하는 게 좋다.

검사 예외를 회피하는 가장 쉬운 방법은 적절한 결과 타입을 담은 옵셔널을 반환하는 것이다(아이템55).

  • 이 방식의 단점은 예외가 발생한 이유를 알려주는 부가 정보를 담을 수 없다는 것이다.
  • 반면, 예외를 사용하면 구체적인 예외 타입과 그 타입이 제공하는 메서드들을 활용해 부가 정보를 제공할 수 있다(아이템70).

검사 예외를 회피하는 또 다른 방법은, 검사 예외를 던지는 메서드를 2개로 쪼개 비검사 예외로 바꾸는 것이다.

try {
    obj.action(args);
} catch (TheCheckedException e) {
    ... // 예외 상황에 대처한다.
}
  • 검사 예외를 던지는 메서드(리팩터링 전)
if (obj.actionPermitted(args)) {
    obj.action(args);
} else {
    ... // 예외 상황에 대처한다.
}
  • 상태 검사 메서드와 비검사 예외를 던지는 메서드(리팩터링 후)
    • actionPermitted는 상태 검사 메서드에 해당하므로 아이템69에서 말한 단점도 그대로 적용되니 주의해야 한다.
    • 외부 동기화 없이 여러 스레드가 동시에 접근할 수 있거나, 외부 요인에 의해 상태가 변할 수 있다면 이 리팩터링은 적절하지 않다.
    • actionPermitted가 action 메서드의 작업 일부를 중복 수행한다면 성능 상 손해이니, 이 리팩터링이 적절하지 않을 수 있다.