Exception? - 체크예외와 언체크예외

Exception?

Exception은 주로 자바에서 제공하는 java.lang.Exception 클래스와 Exception 클래스의 서브클래스들이 쓰이는 상황을 말한다.

예외는 체크 예외(Checked Exception)와 언체크 예외(Unchecked Exception), 두 가지로 나눌 수 있다. 언체크 예외는 RuntimeException을 상속한 것들을 말하고, 체크 예외는 이외의 예외들을 말한다. 물론, RuntimeException 또한 Exception 클래스의 서브 클래스이지만, 프로그램이 동작하는 상황에서 발생하는 예외를 처리한다는 점에서 조금 특별하게 취급한다.

그림1.png

체크 예외

체크 예외는 RuntimeException을 상속하지 않는 예외들을 말하는데, 체크 예외가 발생할 수 있는 메소드를 사용할 경우, 복구가 가능한 예외들이기 때문에 반드시 예외를 처리하는 코드를 함께 작성해야 한다. catch문으로 예외를 잡든, throws로 예외를 자신을 호출한 클래스로 던지는 방법으로 해결해야 하는데, 이를 해결하지 않으면 컴파일 에러 가 발생한다.

대표적으로는 IOException이나 SQLException 등이 존재한다.

언체크 예외

RuntimeException을 상속한 예외들은 따로 언체크 예외라고 부르는데, 명시적으로 예외처리를 강제하지 않기 때문이다. 언체크 예외는 따로 런타임 예외라고도 부른다. 언체크 예외는 따로 catch문으로 잡거나, throws로 선언하지 않아도 된다. 언체크 예외는 프로그램에 오류가 있을 때 발생하도록 의도된 것들이다.

대표적으로는 NullPointerException이나 IllegalArgumentException 등이 존재한다.

일반적인 예외 처리 방법

예외 복구

예외 복구는 예외 상황을 파악하고, 문제를 해결해서 정상적인 상태로 돌려놓는 것을 말한다.

예를 들어 사용자가 요청한 파일을 읽으려고 했지만 파일이 없는 경우, IOException이 발생한다. 이때는 사용자에게 상황을 알리고 다른 파일을 이용하도록 안내하는 방법으로 해결할 수 있다.

이런 식으로, 예외처리 코드를 강제하는 체크 예외들은 어떤 식으로든 복구할 가능성이 있는 경우에 사용된다.

예외처리 회피

예외처리 회피는 말 그대로, 자신이 예외를 처리하지 않고 호출한 쪽으로 throws를 해버리는 것이다.

1
2
3
4
5
try {
    //code
} catch(IOException ioe) {
    throws ioe;
}

이런 방법은 자신을 호출한 쪽에서 예외를 처리하는게 맞다는 확신이 있을 경우에 사용하는 방법이다. 처리를 하는 부분이 없이 무책임하게 계속해서 throws를 하다보면 결국에는 서버에까지 예외가 던져지게되고, 문제가 발생할 수 있다.

예외 전환

위에서 설명한 예외처리 회피와 비슷하게, 예외를 복구해서 정상적인 상태로 만들 수 없기 때문에 예외를 발생한 메소드 밖으로 던지는 방법이지만, 적절한 예외로 전환해서 던지는 방법이다.

예외 전환은 아래의 두 가지 목적으로 사용된다.

  1. 발생한 예외를 의미있는 예외로 바꾸어주기 위해서
  2. 예외를 처리하기 쉽고 단순하게 하기 위해서 포장하는 것

1번은 예외를 던지는 경우, 예외의 이름을 보고 어떤 문제가 있는 예외인지 알 수 있게 해준다. 예를 들어, 사용자의 아이디가 겹치는 예외의 경우 일반적인 SQLException이 아니라, DuplicatedUserIDException으로 던지게 되면, 호출한 쪽에서는 단순히 SQLException이 아닌, 사용자의 아이디가 겹쳐서 발생하게된 예외인지를 인식할 수 있게 된다.

2번은 복구 가능한 예외가 아닌경우, RuntimeException으로 포장해서 던지는 방법이다. 이렇게 체크 예외를 언체크 예외인 RuntimeException으로 포장해서 던지는 경우, 불필요한 throws 구문이 줄게 된다.

1번과 2번의 경우, 생성한 새로운 런타임 예외에 기존의 예외정보를 담는 중첩 예외방식으로 새로운 런타임 예외를 던지는 방법을 많이 사용한다. 기존의 예외를 담아서 던지게되면, 처리하는 곳에서는 getCause()함수를 사용해서 기존에 발생한 예외를 확인할 수 있게 된다.

출처: 토비의 스프링 Chapter 04. 예외