예외 계층

Error
: 애플리케이션에서 복구 불가능한 시스템 예외 -> catch
로 상위 예외를 잡으면 하위 예외까지 같이 잡히기 때문에 Exception부터 필요한 예외로 생각하고 잡으면 됨
Exception
: 체크 예외, 실질적 최상위 예외, 하위 예외까지 모두 컴파일러가 체크하는 체크 예외
RuntimeException
: 언체크 예외, 자식 예외까지 모두 컴파일러가 체크하지 않는 예외로 런타임 예외라고 함
예외 기본 규칙
- 예외를 처리하지 못하면 호출한 곳으로 예외를 계속 던지게 됨
- 예외를 처리하면 이후에 애플리케이션 로직이 정상 흐름으로 동작함
- 예외를 잡거나 던질 때 지정한 예외뿐만 아니라 자식들도 함께 처리됨
- 예외를 처리하지 못하고 계속 던지면 자바 main() 스레드는 예외 로그를 출력하면서 시스템 종료, 웹 애플리케이션은 예외 때문에 시스템이 종료되면 안되기 때문에 WAS가 예외를 받아서 처리하고 오류 페이지를 표시함
체크 예외
Exception
을 상속받은 예외는 체크예외가 됨
- 오류 메시지를 보관하는 기능은 생성자를 통해서 사용
catch{..}
를 통해 처리하며 예외를 지정하면 해당 예외와 하위 타입 예외를 모두 잡아줌
- 체크 예외를 처리할 수 없을 때는
method() throws 예외
를 사용해서 밖으로 던질 예외를 필수로 지정해줘야 함, 그렇지 않으면 컴파일 에러가 발생 -> 개발자가 실수로 예외를 누락하지 않도록 해줌
- 모든 체크 예외를 반드시 잡거나 던지도록 처리해야 하므로 번거로움
언체크 예외
RuntimeException
과 그 하위 예외
- 컴파일러가 예외를 체크하지 않으며, thorws를 선언하지 않고 생략 가능
- 신경쓰고 싶지 않은 언체크 예외를 무시할 수 있으며, 의존 관계를 참조하지 않아도 됨
- 개발자가 실수로 예외를 누락할 수 있음
체크 예외 활용
기본 원칙
- 기본적으로 언체크 예외를 사용
- 체크 예외는 비즈니스 로직상 중요해서 의도적으로 던지는 예외에만 사용 ex) 계좌 이체 실패, 결제 시 포인트 부족, 로그인 ID/PW 불일치 예외
체크 예외의 문제
- 서비스에서 SQLException, ConnectException과 같은 체크 예외가 발생하면 애플리케이션에서 처리할 방법이 없으므로 예외를 밖으로 던져야 함
- 복구 불가능한 예외 : method() throws SQLException, ConnectException을 사용 -> 웹 애플리케이션의 경우 ControllerAdvice 에서 예외를 처리, 사용자에게 오류 메시지를 표시하고 상태코드 500을 표시하여 개발자가 빨리 처리하도록 함
- 서비스 입장에서 신경 쓸만한 에러가 아니더라도 무조건 에러를 처리해야하는 문제 발생
- 의존 관계 문제: 체크 예외이므로 처리할 수 없어도 throws를 통해 예외를 던져야 함 -> 서비스, 컨트롤러에서 JDBC에 의존하게 됨 -> 사용 기술을 JPA로 변경 시 코드를 변경해야함
언체크 예외 활용
- SQLException을 RuntimeSQLException으로 변환 -> 예외를 처리할 수 없을때 선언 없이 두면 됨
- 런타임 예외는 대부분 복구 불가능한 예외임 -> 서비스나 컨트롤러가 신경쓰지 않아도 됨
- throws 생략이 가능 -> 체크예외처럼 예외를 강제로 의존하지 않아도 됨
- 런타임 예외는 문서화하거나 스프링 JdbcTemplate 사용하는 것이 좋음
예외 포함과 스택 트레이스
- 예외를 전환할 때는 기존 예외를 포함해야 함 -> 포함하지 않으면 기존에 발생한 예외와 스택 트레이스 확인이 불가능
- 로그 출력 시 마지막 파라미터에 예외를 넣어주면 예외의 스택 트레이스 출력 가능
ex ) log.info("message={},"message",ex)