검사 예외는 제대로 활용한다면, API와 프로그램의 질을 높일 수 있다.
결과를 코드로 반환하거나 비검사 예외를 던지는 것과 달리, 발생한 문제를 프로그래머가 직접 처리하여 안전성을 높일 수 있기 때문이다.
검사 예외는 필수로 예외를 처리해야 한다는 점, 검사 예외를 던지는 메서드는 스트림 안에서 직접 사용할 수 없다는 점등으로 인해 자바 8부터 부담이 커졌다. 따라서 검사 예외는 필요한 곳에만 쓰고 남용하지 않는 것이 좋다.
검사 예외
: API를 제대로 사용해도 발생할 수 있는 예외거나, 프로그래머가 의미 있는 조치를 취할 수 있는 경우에 사용비검사 예외
: 복구할 방법이 없는 경우에 사용만약 아래의 두가지 방식보다 더 나은 대안이 없다면, 비검사 예외를 선택하자.
} catch (TheCheckedException e) {
throw new AssertionError(); // 일어날 수 없다!
}
} catch (TheCheckedException e) {
e.printStackTrace(); // 이런, 우리가 졌다.
System.exit(1);
}
검사 예외를 회피하는 가장 쉬운 방법은 적절한 결과 타입을 담은 옵셔널을 반환하는 것이다.(아이템 55) 검사 예외를 던지는 대신, 단순 빈 옵셔널을 반환하면 된다.
하지만 예외를 사용할 때 구체적인 예외 타입과 그 타입이 제공하는 메서드들을 활용해 부가 정보를 제공할 수 있는 반면 옵셔널은 예외가 발생한 이유를 알려주는 부가 정보들을 담을 수 없다는 단점이 있다.
두번째로, 검사 예외를 던지는 메서드를 2개로 쪼개 상태 검사 메서드와 비검사 예외를 던지는 메서드로 바꿀 수 있다.
try {
obj.action(args);
} catch (TheCheckedException e) {
... // 예외 상황에 대처한다.
}
리팩터링 하면 다음과 같다.
if (obj.actionPermitted(args)) { // 상태 검사 메서드
obj.action(args);
} else {
... // 예외 상황에 대처한다.
}
하지만 아이템 69에서 얘기했듯이 상태 검사 메서드는 외부 동기화 없이 여러 스레드가 동시에 접근할 수 있거나 외부 요인에 의해 상태가 변할 수 있는 상황에서 안전하지 않다. actionPermitted
와 action
호출 사이에 객체의 상태가 변할 수 있기 때문이다.
📚 핵심 정리
꼭 필요한 곳에만 사용한다면 검사 예외는 프로그램의 안전성을 높여주지만, 남용하면 좋지 않은 API을 야기한다. API 호출자가 예외 상황에서 복구할 방법이 없다면 비검사 예외를 던진다. 복구가 가능하고 호출자가 그 처리를 해주길 바란다면, 우선 옵셔널을 반환해도 될지 고민하자. 옵셔널만으로는 상황을 처리하기에 충분한 정보를 제공할 수 없을 때만 검사 예외를 던져야 한다.