Checked Exception과 Unchecked Exception
주제인 Checked Exception과 Unchecked Exception에 대해 알아보기 전에 Error과 Exception에 대해 간단히 확인해보려고 한다.
Error
- 프로그램 실행 중 발생하는 예기치 않은 문제로, 주로 시스템 수준에서 발생한다.
- 발생 시점에 따라 3가지로 분류된다.
- 컴파일 에러
- 컴파일 단계에서 오류가 발견되면 컴파일러가 에러 메시지를 출력한다.
- 컴파일 에러의 대표적인 원인으로 syntax error가 있다.
- 심각한 수준의 에러는 아님
- 런타임 에러
- 컴파일 과정에는 문제가 없었으나 프로그램 실행중 에러가 발생하여 잘못된 결과를 얻었거나 외부적 요인으로 인한 기계 결함으로 프로그램이 비정상적으로 종료된다.
- 개발 과정에서 논리적이지 못한 설계로 인한 발생이 주요 원인
- 런타임 에러 발생 시 개발자가 역추적하여 원인 파악
- 논리적 에러
- 프로그램 실행과 작동에는 문제를 발생시키지 않지만 사용자의 의도대로 결과가 도출되지 않은 문제를 발생시킨다.
Exception
- 프로그램 실행 중 발생할 수 있는 예측 가능한 문제로, 주로 코드 수준에서 발생한다.
- Checked Exception과 Unchecked Exception으로 구분
=> Runtime Exception을 상속하지 않은 클래스는 Checked Exception, 상속한 클래스는 Unchecked Exception
UnChecked Exception
- 컴파일 때 체크되지 않고 Runtime에 발생하는 예외를 의미
- 명시적인 예외 처리*를 강제하지 않기 때문에 UnChecked Exception이라 부름.
명시적인 예외 처리란?
try-catch로 예외를 잡거나 throw로 호출한 메소드에게 예외를 던지지 않아도 됨을 의미
- 명시적인 예외 처리를 강제하기 때문에 Checked Exception이라 부름.
- 반드시 try-catch로 예외를 잡거나 throw로 호출한 메소드에게 예외를 던져야 한다.
Checked Exception | Unchecked Exception | |
확인 시점 | 컴파일 시점 | 런타임 시점 |
처리 여부 | 반드시 예외처리 | 명시적으로 강제 x |
트랜잭션 처리 | 예외 발생시 롤백 x | 예외 발생시 롤백해야 함 |
종류 | IOException, ClassNotFoundException 등 |
NullPointerException, ClassCastException 등 |
예외 처리 방식
예외처리를 하는 방식에는 3가지 정도가 있다.
- 예외 복구
- 예외 상황을 파악한 후 문제를 해결하여 정상의 상태로 돌려놓음
- Exception이 발생해도 어플리케이션은 정상적으로 동작함
- 반복문을 활용하여 예외가 발생하면 일정 횟수만큼 재시도하여 예외 복구 시도
final int MAX_RETRY = 100;
public Object someMethod() {
int maxRetry = MAX_RETRY;
while(maxRetry > 0) {
try {
// ...
return; // 성공시 바로 리턴
} catch(Exception e) {
// 예외 발생시 로그를 출력
} finally {
// 리소스 반납 및 정리 작업
}
--maxRetry; // 실패하면 1000번 반복
}
// 최대 재시도 횟수를 넘기면 직접 예외를 발생
throw new RetryFailedException();
}
- 예외 처리 회피
- 예외 처리를 자신이 담당하지 않고 자신을 호출한 쪽으로 던져버리는 방법 ( throws )
- 호출한 쪽에서 예외를 처리하는 것이 바람직하다고 판단될 때 사용
- 무분별하게 사용되면 코드의 퀄리티가 떨어질 수 있어 추천되는 방식 x
public void add() throws SQLException {
try {
// ... 생략
} catch(SQLException e) {
e.printStackTrace(); // 로그만 출력하고
throw e; // 다시 날린다
}
}
- 예외 전환
- 적절한 예외로 필터링하여 자신을 호출할 쪽으로 던져버리는 방법
- 좀 더 명확한 의미를 전달하기 위해 적합한 의미를 가진 예외로 변경하여 전달
// 조금 더 명확한 예외로 던진다.
public void add(User user) throws DuplicateUserIdException, SQLException {
try {
// ...
} catch(SQLException e) { // SQLException 예외가 발생하면
if(e.getErrorCode() == MysqlErrorNumbers.ER_DUP_ENTRY) { // 그리고 정확히 어떠한 에러인걸 알았다면
throw DuplicateUserIdException(); // 상위 클래스가 아닌 정확한 예외클래스를 던진다
}
else {
throw e;
}
}
}