티스토리 뷰

꼭 필요한 곳에만 사용한다면 검사 예외는 프로그램의 안전성을 높여주지만,
남용하면 쓰기 고통스러운 API를 낳는다.

 

📢 검사 예외

결과를 코드로 반환하거나 비검사 예외를 던지는 것과 달리,

검사 예외는 발생한 문제를 프로그래머가 처리하여 안정성을 높이게끔 해준다.

물론, 검사 예외를 과하게 사용하면 오히려 쓰기 불편한 API가 된다.

 

어떤 메서드가 검사 예외를 던질 수 있다고 선언됐다면,

이를 호출하는 코드에서는 catch 블록을 두어 그 예외를 붙잡아 처리하거나 더 바깥으로 던져 문제를 전파해야만 한다.

API를 제대로 사용해도 발생할 수 있는 예외이거나, 프로그래머가 의미 있는 조치를 취할 수 있는 경우라면 이 정도 부담은 감안할 수 있다. 

하지만 둘 다 해당하지 않는다면 비검사 예외를 사용하는 것이 좋다.

 

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

이미 다른 검사 예외도 던지는 상황이었다면, catch문 하나 추가하는 선에서 끝나지만,

단 하나의 검사예외를 던진다면 오직 그 예외때문에 try블록을 추가해야 하고 스트림에서 직접 사용하지 못하게 된다.

이런 상황이라면 검사 예외를 안 던지는 방법이 없는지 고민해야 한다.

 

🔎 검사 예외를 회피하는 방법

1. 적절한 결과 타입을 담은 옵셔널을 반환하는 것이다.

검사 예외를 던지는 대신 단순히 빈 옵셔널을 반환하면 된다.

이 방식의 단점은 예외가 발생한 이유를 알려주는 부가 정보를 담을 수 없다는 것이다.

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

 

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

이 방식에서 첫 번째 메서드는 예외가 던져질지 여부를 boolean 값으로 반환한다.

// 검사 예외를 던지는 메서드 - 리팩터링 전
try{
	obj.action(args);
} catch (TheCheckedException e) {
	... //예외 상황에 대처한다.
}
// 상태 검사 메서드와 비검사 예외를 던지는 메서드 - 리팩터링 후
if(obj.actionPermitted(args)){
	obj.action(args);
} else {
	... //예외 상황에 대처한다.
}

리펙터링 후의 API가 딱히 더 아름답진 않지만, 더 유연하다.

한편, actionPermitted는 상태 검사 메서드에 해당하므로 Item 69에서 말했던 단점이 적용되니 주의해야 한다.

(반복문에 예외를 사용하면 장황하고 헷갈리며, 속도도 느리고, 엉뚱한 곳에서 발생한 버그를 숨기기도 한다.)

즉, 외부 동기화 없이 여러 스레드가 동시에 접근할 수 있거나 외부 요인에 의해 상태가 변할 수 있다면 이 리팩터링은 적절하지 않다.

 

💡 정리

꼭 필요한 곳에서만 사용한다면 검사 예외는 프로그램의 안전성을 높여주지만, 남용하면 쓰기 고통스러운 API를 낳는다.
API 호출자가 예외 상황에서 복구할 방법이 없다면 비검사 예외를 던지자.
복구가 가능하고 호출자가 그 처리를 해주길 바란다면, 우선 옵셔널을 반환해도 될지 고민하자.
옵셔널만으로는 상황을 처리하기에 충분한 정보를 제공할 수 없을 때만 검사 예외를 던지자.
댓글
공지사항
최근에 올라온 글