관련 포스트: 220111 CustomException 리팩토링
예외(Exception): 입력 값에 대한 처리가 불가능하거나, 프로그램 실행 중에 참조된 값이 자못된 경우 등 프로그램의 흐름에 어긋나게 하는 상황 (로직에서 발생한 실수 혹은 사용자의 영향)
오류(Error): 시스템에 뭔가 비정상적인 상황이 발생한 경우. 주로 JVM 이 발생시키는 것이며 이는 애플리케이션 코드에서 잡으려고 해도 방법이 없다. (시스템이 종료되어야 하는 수습할 수 없는 상황) OutOfMemoryError
ThreadDeath
StackOvefflowError
등이 있다.
오류와 에러의 상속 관계
자바 예외 (+오류)
이 둘을 나누는 기준은 꼭 처리해야 하느냐이다.
CheckedException 이 발생할 가능성이 있는 로직은 반드시 복구, 회피, 처리 해줘야 하지만, UncheckedException 은 명시적인 예외처리를 하지 않아도 된다 (피할 수 있지만, 개발자가 부주의해서 발생하는 경우가 대부분이며 미리 예측할 수 있는 상황에서 발생하는 예외이르모 굳이 로직으로 처리를 할 필요가 없다) .
RuntimeException 을 상속받는 모든 예외.
컴파일 시점에 예외를 catch 하는지 확인하지 않는다 => 컴파일 시점에 예외가 발생하는지 여부를 판단할 수 없다.
트랜잭션 Rollback 이 된다 (잘 와닿지 않는다).
예외가 발생하는 메서드에서 throws 예약어를 활용해 예외를 처리할 필요가 없다.
RuntimeException 을 상속받지 않는 모든 예외.
Compile Exception 이라고도 한다. 말 그대로 컴파일시점에 예외를 catch 하는지 정적으로 확인한다.
만약 컴파일 시점에서 예외에 대한 처리가 안되어있다면 with try/catch 컴파일 에러가 발생한다. 처리를 하지 않았다면 예외가 발생하는 메서드에서 throws 예약어를 활용해서 던져야 한다 (잘 와닿지 않는다).
트랜잭션 Rollback 이 안된다 (잘 와닿지 않는다).
1. 예외 복구
: 예외가 발생해도 앱이 정상적으로 동작하게 한다.
ex. 네트워크 요청 실패시 재시도
static int MAX_RETRY = 10;
int retry = MAX_RETRY;
while (retry > 0) {
retry -= 1;
try{
...시도...
...성공 시 리턴...
} catch(SomeException e) {
// 로그 출력
// 실패 로직 존재 시 원상 복구
// 일정 시간 대기
} finally {
// 리소스 반납 및 정리
}
}
// MAX_RETRY 초과 시 예외 Throw
throw new MAXTRYEXCEPTION();
2. 예외 처리 회피
: 예외가 발생하면 throws 를 통해 호출한쪽으로 던지고 자신의 책임을 없앤다.
// 예시 1
public void add() throws SQLException {
// ...생략
}
// 예시 2
public void add() throws SQLException {
try {
// ... 생략
} catch(SQLException e) {
// 로그를 출력하고 다시 날린다!
throw e;
}
}
3. 예외 전환
: 호출한 쪽에 던지는데, 더 명확하게 인지할 수 있도록 돕는 방법.
// 조금 더 명확한 예외로 던진다.
public void add(User user) throws DuplicateUserIdException, SQLException {
try {
// ...생략
} catch(SQLException e) {
if(e.getErrorCode() == MysqlErrorNumbers.ER_DUP_ENTRY) {
throw DuplicateUserIdException();
}
else throw e;
}
}
ref
https://velog.io/@gillog/Java-Exception-Handling복구-회피-전환
https://toneyparky.tistory.com/40
https://madplay.github.io/post/java-checked-unchecked-exceptions