본문 바로가기

Spring

토비의 스프링 #4. 예외

4.1 사라진 SQLEXCEPTION

4.1.1 초난감 예외처리

예외 블랙홀

// #1
catch (SQLException e){
}

// #2
catch (SQLException e){
 System.out.println(e);
 e.printStackTrace;
}

무의미하고 무책임한 throws

// #3
public void method () throws Exception{
}

4.1.2 예외의 종류와 특징

Error

  • java.lang.Error 시스템의 에러

Exception과 체크 예외

  • 개발자들이 만든 애플리케이션 코드의 작업 중에 예외상황이 발생했을 경우에 사용
  • Exception은 다시 체크 예외와 언체크 예외로 나누어짐
  • 전자는 Exception 클래스의 서브 클래스이면서 RuntimeException을 상속하지 않는 것
  • 후자는 RuntimeException을 상속한 클래스들을 말한다.
  • 체크 예외가 발생할 수 있는 메서드를 사용할 경우 반드시 예외 처리를 하는 코드를 함께 작성해야 한다. catch문으로 잡든 다시 throws를 정의해서 메서드 밖으로 던져야 한다.

⇒ 체크 예외의 불필요성을 주장하는 사람이 많음!!

RuntimeException과 언체크/런타임 예외

  • RuntimeException 클래스를 상속한 예외들은 명시적인 예외처리를 강제하지 않기 때문에 언체크 예외라고 불린다.
  • 런타임 예외는 catch문으로 잡거나 throws로 선언하지 않아도 된다.
  • ex)NullPointerException이나 IllegalArgumentException
  • 개발자가 부주의해서 발생할 수 있는 경우에 발생하도록 만든 것이 런타임 예외다. 따라서 런타임 예외는 예상하지 못했던 예외 상황에서 발생하는게 아니기 때문에 굳이 catch나 throws를 사용하지 않아도 됨

4.1.3 예외처리 방법

예외 복구

  • 예외상황을 파악하고 문제를 해결해서 정상 상태로 돌려놓는 것
  • 사용자에게 상황을 알려주고 다른 파일을 이용하도록 안내해서 예외상황을 해결할 수 있다.
  • 예외가 처리됐으면 비록 기능적으로는 사용자에게 에외상황으로 비쳐도 애플리케이션에서는 정상적으로 설계된 흐름을 따라 진행되어야 한다.
  • 때로는 재시도하도록 예외처리할 수 있다.

예외처리 회피

  • 예외처리를 자신이 담당하지 않고 자신을 호출한 쪽으로 던져버리는 것이다.
  • throws 문으로 선언해서 예외가 발생하면 알아서 던져지게 하거나 catch 문으로 일단 예외를 잡은 후에 로그를 남기고 다시 예외를 던지는 것이다.
  • 예외를 회피하는 것은 예외를 복구하는 것처럼 의도가 분명해야 한다.

예외 전환

  • 예외 회피와 비슷하게 예외를 복구해서 정상적인 상태로는 만들 수 없기 때문에 예외를 메소드 밖으로 던지는 것이다. 하지만 에외 회피와 달리 발생한 예외를 그대로 넘기는게 아니라 적절한 예외로 전환해서 던진다는 특징이 있다.
  • 예외상황에 대한 의미를 분명하게 해줄 수 있는 예외로 바꿔주기 위해

4.1.4 예외처리 전략

런타임 예외의 보편화

add() 메소드의 예외처리

애플리케이션 예외

4.1.5 SQLException은 어떻게 됐나?

4.2 예외 전환

4.2.1 JDBC의 한계

비표준 SQL

호환성 없는 SQLException의 DB 에러정보

4.2.2 DB 에러 코드 매핑을 통한 전환

4.2.3 DAO 인터페이스와 DataAccessException 계층구조

DAO 인터페이스와 구현의 분리

데이터 액세스 예외 추상화와 DataAccessException 계층구조

4.2.4 기술에 독립적인 UserDao 만들기

인터페이스 적용

테스트 보완

DataAccessException 활용 시 주의사항

4.3 정리

  • 예외를 잡아서 아무런 조치를 취하지 않거나 의미 없는 throws 선언을 남발하는 것은 위험하다.
  • 예외는 복구하거나 예외처리 오브젝트로 의도적으로 전달하거나 적절한 예외로 전환해야 한다.
  • 좀 더 의미있는 예외로 변경한거나, 불필요한 catch/throws를 피하기 위해 런타임 예외로 포장하는 두 가지 방법의 예외 전환이 있다.
  • 복구할 수 없는 예외는 가능한 한 빨리 런타임 예외로 전환하는 것이 바람직하다.
  • 애플리케이션의 로직을 담기 위한 예외는 체크 예외로 만든다.
  • JDBC의 SQLException은 대부분 복구할 수 없는 예외이므로 런타임 예외로 포장해야 한다.
  • SQLException의 에러 코드는 DB에 종속되기 때문에 DB에 독립적인 예외로 전환될 필요가 있다.
  • 스프링은 DataAccessException을 통해 DB에 독립적으로 적용 가능한 추상화된 런타임 예외 계층을 제공한다.
  • DAO를 데이터 액세스 기술에서 독립시키려면 인터페이스 도입과 런타임 예외 전환, 기술에 독립적인 추상화된 예외로 전화이 필요하다.