item 71 : 필요 없는 검사 예외 사용은 피하라

검사 예외의 활용과 리팩터링 전략

검사 예외를 싫어하는 자바 프로그래머가 많지만, 제대로 활용하면 API와 프로그램의 질을 높일 수 있다. 검사 예외는 프로그래머가 문제를 직접 처리하여 안전성을 높인다. 하지만 과도한 사용은 불편한 API를 만들어내므로, 필요에 따라 적절하게 사용해야 한다.

1. 검사 예외와 비검사 예외의 차이

1) 검사 예외의 장단점

  • 검사 예외는 메서드에서 발생할 수 있는 예외를 명시하고, 호출하는 코드에서 이를 처리하도록 강제한다. 이로 인해 프로그램의 안정성이 높아진다.

  • 반면에, 검사 예외는 API 사용자에게 부담을 줄 수 있다. 예외를 처리하기 위해 catch 블록을 추가해야 하며, 스트림 API와 같은 기능과 결합하기 어려운 경우도 있다.

검사 예외와 비검사 예외 중 어느 것을 선택할지는 프로그래머가 그 예외를 어떻게 다룰지 생각해보면 알 수 있다.

2) 예외 처리의 예

try {
    obj.action(args);
} catch (TheCheckedException e) {
    // 예외 상황에 대처한다.
}

이러한 방식으로 검사 예외를 처리해야 하며, 이는 API 사용자에게 부담을 줄 수 있다.

2. 검사 예외 대신 사용할 수 있는 대안

1) 옵셔널(Optional) 사용

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

  • 검사 예외 대신 빈 옵셔널을 반환하면, 예외 발생 시 부가 정보를 제공하기 어렵지만, 예외 처리의 부담을 줄일 수 있다.

단점: 옵셔널은 예외 발생 이유에 대한 부가 정보를 제공할 수 없다. 반면 예외를 사용하면 구체적인 예외 타입과 그 타입이 제공하는 메서드를 통해 부가 정보를 전달할 수 있다.

옵셔널을 굳이 사용해야 하는 이유

  • 코드 가독성 향상: 옵셔널을 사용하면 예외 처리 코드의 중복을 줄이고 가독성을 높일 수 있다. 예외를 던지는 대신 빈 옵셔널을 반환하면 코드의 흐름이 깔끔해진다.

  • 불필요한 예외 방지: 옵셔널을 사용함으로써, 예외적인 상황이 아닌 경우에도 불필요하게 예외를 던지는 것을 방지할 수 있다. 예외는 실제로 프로그램의 흐름을 방해하므로, 예외적인 상황이 아닌 경우에는 옵셔널을 사용하는 것이 더 적절하다.

  • 스트림 API와의 호환성: 자바 8부터는 스트림 API가 널리 사용되며, 옵셔널을 사용하면 스트림에서 처리하기가 훨씬 수월하다. 검사 예외는 스트림과 잘 호환되지 않기 때문에 옵셔널을 사용하여 더 직관적이고 효율적인 처리가 가능하다

2) 상태 검사 메서드로 리팩터링

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

  • 첫 번째 메서드는 상태 검사 메서드로 예외 발생 가능 여부를 boolean 값으로 반환한다.

  • 두 번째 메서드는 실제 작업을 수행하는 메서드이다.

  • 이렇게 리팩터링하면 API가 더 유연해지지만, 모든 상황에서 적용할 수 있는 것은 아니다. 특히 외부 동기화 없이 여러 스레드가 동시에 접근할 수 있는 경우에는 적절하지 않다.

3) 리팩터링 예시

리팩터링 전 (검사 예외 사용)

try {
    obj.action(args);
} catch (TheCheckedException e) {
    // 예외 상황에 대처한다.
}

리팩터링 후 (상태 검사 메서드와 비검사 예외 사용)

if (obj.actionPermitted(args)) {
    obj.action(args);
} else {
    // 예외 상황에 대처한다.
}

이 리팩터링은 모든 상황에 적용할 수 있는 것은 아니다. 외부 동기화 없이 여러 스레드가 동시에 접근하거나 외부 요인에 의해 상태가 변할 수 있는 경우에는 이 리팩터링이 적절하지 않다.

3. 검사 예외의 남용 방지

  • 검사 예외는 프로그램의 안전성을 높여주는 장점이 있지만, 남용하면 사용하기 불편한 API를 만들 수 있다.

  • API 호출자가 예외 상황에서 복구할 방법이 없다면 비검사 예외를 던지는 것이 좋다.

  • 복구가 가능하고 호출자가 그 처리를 해주길 바란다면, 우선 옵셔널을 반환할 수 있는지 고민해야 한다.

  • 옵셔널만으로 충분한 정보를 제공할 수 없을 때만 검사 예외를 던져야 한다.

💡 핵심 정리

  • 검사 예외는 꼭 필요한 곳에만 사용해야 한다. 그렇지 않으면 사용자가 부담을 느끼고 API 사용성을 저하시킬 수 있다.

  • API 호출자가 예외 상황에서 복구할 방법이 없다면 비검사 예외를 사용해야 한다.

  • 복구가 가능하다면 옵셔널을 먼저 고려하고, 옵셔널만으로는 충분하지 않을 때 검사 예외를 던지도록 한다.

올바른 예외 처리는 프로그램의 안전성과 유연성을 모두 향상시키는 중요한 요소이다.

Last updated