Spring

[Spring DB 1편 듣고 복습, 토이 프로젝트 수정] 5. 자바 예외 이해

gogi masidda 2024. 3. 2. 12:53

  • Object: 예외도 객체이므로, 예외의 최상위 부모도 Object
  • Throwable: 최상위 예외
  • Error: 메모리 부족이나 시스템 오류같이 애플리케이션에서 복구 불가능한 시스템 예외.
    • Throwable을 catch로 잡으려 하면 Error도 잡혀서 Throwable은 잡으려 하면 안됨. Exception부터 잡아야 하는 오류로 생각해야함.
  • Exceptions
    • 체크 예외: 애플리케이션 로직에서 사용할 수 있는 실질적인 최상위 예외. RuntimeException을 제외하고 Exceptions의 하위 예외는 모두 체크 예외임.
      • 체크 예외는 잡아서 처리하거나, 밖으로 던지도록 선언해야함.
      • 개발자가 실수로 예외를 누락하지 않도록 컴파일러를 통해 문제를 잡아주는 장점이 있지만, 모든 체크 예외를 처리해주어야 하는 번거로움이 생기고, 크게 신경쓰고 싶지 않은 예외도 처리해주어야 한다.
    • 언체크 예외(런타임 예외): 컴파일러가 체크하지 않는 언체크 예외.   
      • 예외를 던지는 throws를 선언하지 않고 생략할 수 있다.
      • 신경쓰고 싶지 않은 언체크 예외를 무시할 수 있고, 예외를 밖으로 던지려고 throws 예외를 선언하지 않아도 되어 쓰고싶지 않은 예외의 의존관계를 참조하지 않아도 된다. 하지만 개발자가 실수로 예외를 누락할 수도 있다는 단점이 있다.

예외의 기본 규칙

  • 예외는 잡아서 처리하거나 던져야 함
  • 예외를 잡거나 던질 때 지정한 예외만이 아니라, 그 예외의 자식들까지 함께 처리됨.

예외를 처리하지 못하고 계속 던지면?

  • 자바 main() 쓰레드의 경우에는 예외 로그를 출력하면서 시스템이 종료
  • 웹 애플리케이션은 종료되면 안되니까 사용자에게 오류 페이지를 보여주어야 함.

예외를 직접 만들 때

  • Exception을 상속 받은 예외는 체크 예외가 된다.
  • RuntimeException을 상속 받은 예외는 언체크 예외가 된다.

예외 활용

 

체크 예외 활용

  • 체크 예외는 비즈니스 로직 상 의도적으로 던지는 예외에만 사용하기
    • 예시
      • 계좌 이체 실패
      • 결제시 포인트 부족
      • 로그인 실패
    • 이 경우를 무조건 체크 예외로 만들어야 하는 것은 아님. 개발자가 놓치면 안되는 심각한 문제는 체크 예외로 만들어서 놓치지 않도록 할 수 있음.
    • 하지만, SQLException의 경우에는 SQL 문법 문제나 데이터베이스 서버 문제가 있을 수 있는데 서비스 입장에서 복구 불가능하여 굳이 알고싶지 않고,  JDBC가 아니라 JPA 기술로 바꾸게 되면 JPAException으로 바꿔야 하는 의존 관계 문제가 발생한다.
    • 실무에서 발생하는 예외는 대부분 시스템 예외라서 복구 불가능한데, 체크 예외를 사용하면 서비스와 컨트롤러가 알아야 하는 불필요한 의존 관계가 발생한다.

언체크 예외 활용

public void call() {
     try {
     	runSQL();
     } catch (SQLException e) {
     	throw new RuntimeSQLException(e); //기존 예외 e 포함
     }
 }

이렇게 SQLException을 RuntimeSQLException으로 전환해서 던지면 서비스나 컨트롤러에서 이 예외에 대해 알지 못해도 된다. 이로써 복구 불가능한 예외를 신경쓰지 않을 수 있고, 의존 관계에 대한 문제도 해결된다. JPA로 바꿔도 서비스 코드를 바꾸지 않아도 된다.

 

런타임 예외는 놓칠 수 있으므로 문서화를 잘해야 한다. 또는 중요한 런타임 예외의 경우에는 throws로 명시하여 인지할 수 있게 해준다.

 

예외를 전환할 때는 꼭 기존 예외를 포함해서 어떤 예외가 전환된 것인지 알려야 한다.

void printEx() {
     Controller controller = new Controller();
     try {
     	controller.request();
     } catch (Exception e) {
     	//e.printStackTrace();
     	log.info("ex", e);
     }
}

System.out에 스택 트레이스를 출력하려면 e.printStackTrace()를 사용하면 된다. 하지만 실무에서는 항상 로그를 사용한다.

log.info의 마지막 파라미터에 예외를 넣어주면 로그에 스택 트레이스를 출력할 수 있다. 

728x90