자바 예외 계층
- Object : 모든 객체의 최상위 부모는 Object이다.
- Throwable : 최상위 예외이다.
- Error : 애플리케이션에서 복구 불가능한 시스템 예외이므로, 해당 예외를 잡으려고 하면 안된다.
- Exception : 체크 예외로 애플리케이션 로직에서 사용할 수 있는 실질적인 최상위 예외로 컴파일러가 체크하는 예외이다.
- RuntimException : 언체크 예외로 런타임 예외로 라고도 부르며 컴파일러가 체크하지 않는 언체크 예외이다.
예외 기본 규칙
예외는 잡아서 처리하거나, 밖으로 던지거나 둘 중 하나이다.
예외를 처리하지 못하면 호출한 곳으로 예외를 계속 던지게 된다. 예외를 잡거나 던질 때 지정한 예외 뿐만 아니라 그 예외의 자식들도 함께 처리된다.
예외를 처리하지 못하고 계속 던질 때
- 자바 main 쓰레드의 경우 예외 로그를 출력하면서 시스템이 종료된다.
- 웹 애플리케이션의 경우 하나의 예외때문에 시스템이 종료되면 안되기 때문에 사용자에게 개발자가 지정한 오류 페이지를 보여준다.
체크 예외
Exception과 그 하위 예외는 모두 컴파일러가 체크하는 체크 예외이다. 단 RuntimeException은 예외이다.
예외를 잡을 때
call()은 Exception 예외가 발생하며 catch를 통해 예외를 잡았다.
public void callCatch() {
try {
repository.call();
} catch (Exception e) {
//예외 처리 로직
log.info("예외 처리, message={}", e.getMessage(), e);
}
}
예외를 밖으로 던질 때
thorws를 통해서 Exception 예외를 던졌다.
public void callThrow() throws Exception {
repository.call();
}
체크 예외의 장단점
체크 예외의 경우 catch로 예외를 잡아서 처리하거나 throws로 예외를 밖으로 던지는 선언을 반드시 해줘야 한다.
- 장점 : 개발자가 실수로 예외를 누락하지 않도록 방지해주는 안전장치 역할을 해준다.
- 단점 : 모든 체크 예외를 처리해야하는 불편함이 있다.
언체크 예외
RuntimException과 그 하위 예외는 언체크로 분류된다. 언체크 예외는 말 그대로 컴파일러가 체크하지 않는 예외이다.
체크 예외와 언체크 예외의 차이
체크 예외와 달리 언체크 예외는 예외를 잡아서 처리하지 않아도 된다. 예외를 잡지 않는다면 자동으로 밖으로 예외를 던진다.
예외를 잡을 때
예외 처리가 필요한 경우 예외를 잡아서 처리하면 된다.
public void callCatch() {
try {
repository.call();
} catch (Exception e) {
//예외 처리 로직
log.info("예외 처리, message={}", e.getMessage(), e);
}
}
예외를 밖으로 던질 때
체크 예외와 달리 throws를 선언하지 않아도 된다. 언체크 예외는 주로 생략하지만 중요한 예외의 경우 throws를 선언하면 된다.
public void callThrow() {
repository.call();
}
언체크 예외의 장단점
언체크 예외의 경우 예외를 잡아서 처리할 수 없을 때, 예외를 밖으로 던지는 throws를 생략할 수 있다.
- 장점 : 신경쓰지 않는 언체크 예외를 무시할 수 있다.
- 단점 : 개발자가 실수로 예외를 누락할 수 있다.
체크 예외 활용
체크 예외와 언체크 예외의 차이는 예외를 처리할 수 없을 때 예외를 밖으로 던지는 부분에 있으며 이 부분을 필수로 선언해야 하는가 안하는가에 있다.
체크 예외의 기본원칙
- 기본적으로 언체크(런타임) 예외를 사용하자.
- 체크 예외는 비지니스 로직상 정말 중요한 부분에만 사용하자.
체크 예외의 문제점
체크 예외는 개발자가 실수로 예외를 놓치는 것을 방지해주기 때문에 언체크보다 매우 안전하다. 근데 왜 기본적으로 언체크 예외를 사용할까?
1. 복구 불가능한 예외
해당 사진 처럼 예외가 발생할 때 서비스나 컨트롤러에서 SQLException 와 ConnectException 예외를 처리할 수가 없다.
대부분의 예외는 복구가 불가능하므로 서비스나 컨트롤러에서 이런 문제들을 복구하는 것은 어렵다. 따라서 이런 문제들을 일관성있게 공통으로 처리해야 한다. 오류 로그를 남기고 개발자가 해당 오류를 빠르게 인지하는 것이 필요하다.
2. 의존 관계에 대한 문제
체크 예외의 경우 컨트롤러나 서비스에서 예외를 처리할 수 없어도 throws를 통해 던지는 예외를 선언해야하며, 이 과정에서 특정 Exception에 대해서 의존을 하게 된다. 만약 JDBC 기술에서 JPA 기술로 변경하게 되면 많은 부분들을 전부 변경해야 하는 번거로움이 생기게 된다.
언체크 예외 활용
기존 SQLException 이나 ConnectionException은 체크 예외이다. 해당 예외들을 언체크(런타임) 예외로 바꾼다면 많은 문제들을 해결할 수 있다.
SQLException을 RuntimeSQLException으로 ConnectException을 RuntimeConnectException으로 변환했다.
해당 예외는 언체크 예외이기 때문에 예외들을 별도의 선언이 필요없다.
체크 예외를 언체크 예외로 변환할 때
런타임 예외로 변환할 때 반드시 기존 예외를 포함시켜줘야 예외 출력시 스택 트레이스에서 기존 예외를 함께 확인할 수 있다.
public void call() {
try {
runSQL(); // SQLException
} catch (SQLException e) {
throw new RuntimeSQLException(e);
}
런타임 예외 변환시 효과
중간에 기술이 변환돼도 예외를 사용하지 않는 컨트롤러나 서비스에서는 코드를 변경하지 않아도 된다.
추가로 런타임 예외는 놓칠 가능성이 있기 때문에 예외 문서화를 하는 과정도 매우 중요하다.
예외 포함과 스택 트레이스
예외를 변환시 꼭 기존 예외를 포함시켜야 한다.
try {
controller.request();
}catch (Exception e) {
log.info("ex", e);
}
try {
runSQL();
}catch (SQLException e) {
throw new RuntimeSQLException(e); //기존 예외(e) 포함
}
와 같이 로그를 출력할 때 마지막 파라미터에 예외를 넣어주면 로그에 스택 트레이스를 출력할 수 있다.
출처 : 인프런 - 스프링 DB 1편 feat.김영한 쌤
'웹 개발' 카테고리의 다른 글
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 - 검증 (0) | 2024.05.30 |
---|---|
intellij 단축키 (0) | 2024.04.16 |
스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 (2) | 2024.02.27 |
스프링 DB 1편 - 데이터 접근 핵심 원리 (0) | 2024.02.24 |
스프링 MVC 2편 - 타임리프 (0) | 2024.02.23 |