본문 바로가기
spring/토비의 스프링

토비의 스프링 Vol. 1 정리 - 4장 예외 - 1 예외의 종류

by Empering 2020. 4. 24.
반응형

토비의 스프링 Vol. 1 정리 - 4 - 1 예외의 종류

4장 예외


예외

JdbcTemplate을 대표로 하는 스프링의 데이터 액세스 기능에 있는 예외처리와 관련된 접근 방법에 대해 알아본다. 이를 통해 예외를 처리하는 베스트 프랙티스도 살펴본다.

 

부적절한 예외처리

> 예외 블랙홀

        try {
            // ...
        } catch (SQLException e) {
            // 예외를 잡고는 아무것도 하지 않는다.
        }
        
        // 예외발생 시 콘솔에 출력 1
        } catch (SQLException e) {
            System.out.println(e);
        }
        
        // 예외발생 시 콘솔에 출력 2
        } catch (SQLException e) {
            e.printStackTrace();
        }

예외가 발생하면 그것을 catch 블록을 써서 잡아내는 것까지는 좋은데 그리고 아무것도 하지 않고 별문제 없는 것처럼 넘어가 버리는 것은 위험한 일이다. 프로그램 실행 중에 어디선가 오류가 있어서 예외가 발생했는데 그것을 무시하고 계속 진행해버리기 때문이다. 결국 발생한 예외로 인해 어떤 기능이 비정상적으로 동작하거나, 메모리나 리소스가 소진되거나, 예상치 못한 다른 문제를 일으킬 것이다. 더 큰 문제는 시스템 오류나 이상한 결과의 원인이 무엇인지 찾아내기가 매우 힘들다는 점이다.

콘솔에 출력해주는 예외처리도 문제다. 개발 중에는 IDE콘솔에 이 메시지가 눈에 확 띄게 보이니 문제가 생겨도 금방 알아차리고 조치를 취할 수 있지만, 운영서버에 올라가면 콘솔 로그를 누군가가 계속 모니터링 하지 않는 한 이 예외 코드는 심각한 폭탄으로 남아 있을 것이다. 예외 메시지를 출력한 것은 예외를 처리한 것이 아니다.

모든 예외는 적절하게 복구되든지 아니면 작업을 중단시키고 운영자 또는 개발자에게 분명하게 통보돼야 한다.

 

> 무의미하고 무책임임한 throws

    public void method1() throws Exception { // 예외 전달
        method2();
        // ...
    }
    
    public void method2() throws Exception { // method1()로 예외 전달
        method3();
    }
    
    public void method3() throws Exception { // method2()로 예외 전달
        // ...
    }

API 등에서 발생하는 예외를 일일히 catch하기도 귀찮고, 매번 정확하게 예외 이름을 적어서 선언하기도 귀찮으니 아예 throws Exception 이라는 모든 예외를 무조건 던져버리는 선언을 모든 메소드에 기계적으로 넣는 것이다. 이런 무책임한 throws 선언도 심각한 문제점이 있다.

자신이 사용하려고 하는 메소드에 throws Exception 이 선언되어 있다고 생각해보면, 그런 메소드 선언에서는 의미 있는 정보를 얻을 수 없다. 정말 무엇인가 실행중에 예외적인 상황이 발생할 수 있다는 것인지, 아니면 그냥 습관적으로 복사해서 붙여놓은 것인지 알 수가 없다. 결국 이런 메소드를 사용하는 메소드에서도 역시 throws Exception을 따라서 붙이는 수밖에 없다. 결과적으로 적절한 처리를 통해 복구될 수 있는 예외상황도 제대로 다룰 수 있는 기회를 박탈당한다.

 

예외의 종류와 특징

> Error

java.lang.Error 클래스의 서브 클래스들이다. 시스템에 비정상적인 상황이 발생했을 경우에 사용된다. 주로 자바 VM에서 발생시키는 것이고 애플리케이션 코드에서 잡으려고 하면 안 된다. OutOfMemoryError, ThreadDeath같은 에러는 catch 블록으로 잡아봤자 아무런 대응 방법이 없기 때문이다.

 

> Exception과 체크 예외

java.lang.Exception 클래스와 그 서브클래스로 정의되는 예외들이다. 에로와 달리 개발자들이 만든 애플리케이션 코드의 작업 중에 예외상황이 발생했을 경우에 사용된다.

Exception은 다시 체크 예외와 언체크 예외로 구분된다. 체크예외는 Exception의 서브클래스이면서 RuntimeException 클래스를 상속하지 않은 것들이고, 언체크 예외는 RuntimeException을 상속한 클래스들을 말한다.

일반적으로 예외라고 하면 Exception 클래스의 서브클래스 중에서 RuntimeException을 상속하지 않은 것만을 말하는 체크 예외라고 생각해도 된다. 체크 예외가 발생할 수 있는 메소드를 사용할 경우 반드시 예외를 처리한는 코드를 함께 작성해야 한다. 그렇지 않으면 컴파일 에러가 발생한다.

 

> RuntimeException과 언체크/런타임 예외

java.lang.RuntimeException 클래스를 상속한 예외들이다. 명시적인 예외처리를 강제하지 않기 때문에 언체크 예외라고도 불리거나 런타임 예외라고도 한다.

런타임 예외는 주로 프로그램으 ㅣ오류가 있을 때 발생하도록 의도된 것들이다. 대표적으로는 NullPointerException, IllegalArgumentException 등이 있다. 런타임 예외는 예상하지 못했던 예외상황에서 발생하는 것이 아니기 때문에 굳이 catch나 throws를 강제하지 않는다.

 

반응형

댓글