Exception 알아보기 (Checked Exception, Unchecked Exception)

mallin·2022년 6월 1일
1

JAVA

목록 보기
2/6
post-thumbnail

예외 및 에러

에러(Error) 는 시스템에 무엇인가 비정상적인 상황이 발생한 경우에 사용된다.
주로 자바 가상 머신(JVM) 에서 발생시키는 것이며 예외와 반대로 이를 애플리케이션 코드에서 잡으려고 하면 안 된다.
EX) OutOfMemoryError, ThreadDeath, StackOverflowError

예외(Exception) 란 개발자의 실수로 예기치 않은 상황이 발생했을 때
입력 값에 대한 처리가 불가능하거나, 프로그램 실행 중에 참조된 값이 잘못된 경우 등 정상적인 프로그램의 흐름을 어긋나는 것을 말한다.
그리고 자바에서 예외는 개발자가 직접 처리할 수 있기 때문에 예외 상황을 미리 예측하여 핸들링할 수 있다.

예외는 ① Checked 와 ② Unchecked 두개로 나뉜다.

Checked Exception vs Unchecked Exception

RuntimeException을 상속하지 않는 클래스는 Checked Exception,
반대로 상속한 클래스는 Unchecked Exception으로 분류할 수 있다.


출처 : https://madplay.github.io/post/java-checked-unchecked-exceptions

자바에서는 RuntimeException 및 이를 상속한 클래스를 명시적으로 예외처리를 하지 않아도 되도록 특별 취급 해준다.

Checked Exception

  • RuntimeException 의 하위 클래스가 아니면서 Exception 클래스의 하위 클래스
  • 반드시 에러 처리를 해줘야 함
  • 컴파일 시점에 확인된 exception

EX)
IOException : 입출력 예외가 발생했을 때
SQLException : 데이터베이스 액세스 오류 또는 기타 오류에 대한 정보를 제공하는 예외
ClassNotFoundException : 동적으로 클래스를 문자열로 로딩하다가 클래스가 없는 경우
FileNotFoundException : 지정된 파일을 찾을 수 없을 때


Checked Exception 중 하나인 FileNotFoundException 은 IOException 을 상속 받고 있다.

Unchecked Exception

  • RuntimeException 의 하위 클래스
  • 에러 처리를 강제하지 않음
  • 실행 중에(runtime) 에 발생할 수 있는 예외

EX)
ArrayIndexOutOfBoundsException : 배열의 범위를 벗어났을 때
NullPointerException : 값이 null이 참조변수를 참조했을 때

해당 exception 들이 에러 처리를 강제하게 되면, 리스트에서 값을 꺼내서 사용하거나 ..
참조하거나 할 때마다 에러 처리를 해줘야 하기 때문에 강제 하진 않는다.

List<String> testList = new ArrayList<>();
testList.add("테스트1");
testList.add("테스트2");

String testStr = testList.get(0);
try {
	String testStr = testList.get(0);
catch(ArrayIndexOutOfBoundsException e) {
	...
}

NullPointerException 을 보면 RuntimeException 을 상속 받고 있는 걸 알 수 있다.

코드에서 살펴보기

Checked Exception 인 FileNotFoundException 의 경우엔 따로 에러처리를 하지 않았을 때 인텔리제이에서 오류라고 알려주는 걸 볼 수 있고,

Unchecked Exception 인 NullPointerException 의 경우엔 따로 에러처리를 하지 않아도, 오류가 발생하지 않는 걸 확인 할 수 있다.

그렇다면 Checked Exception 은 어떻게 예외 처리 해줘야 할까 ?

빨간줄 (오류) 가 발생한 코드에 마우스를 올리면 인텔리제이에서는 아래👇와 같이 총 3가지의 방법을 추천해준다.

① Add exception to method signature

이 방법은 해당 exception 을 메소드에 throws 를 추가해 상위로 던져 버리는 방법이다.
쉽게 사용할 수 있지만, 상위 메소드에서 해당 exception 에 대한 처리가 없는 경우엔 유의해서 사용해야 한다.

② Surround with try/catch

try-catch 를 통해 예외를 잡아서 처리하는 방법이다.
catch 에 예외 처리를 해주면 되는 방식이다. 보통 이 방법으로 많이 예외를 처리한다.

③ Annotate method 'getTest' as @SneakyThrows

롬복에서 지원하는 @SneakyThrows 를 사용하는 방법이다. 👉 공식문서
checked exception 을 슬쩍 던지는데 사용한다. 하지만, 다소 논쟁의 요소가 있기 때문에 신중하게 사용하는게 좋다.
내부적으로 throw 된 checked 예외를 무시, 래핑, 교체 또는 수정하지 않고 단순히 컴파일러는 가짜로 만든다.

예외 처리

예외를 처리하는 방법에는 ① 예외 복구, ② 예외 처리 회피, ③ 예외 전환의 방법이 있다.

예외 복구

예외 상황을 파악하고 문제를 해결해서 정상 상태로 돌려놓는 방법

  • 예외를 잡아서 일정 시간, 조건만큼 대기하고 다시 재시도를 반복한다.
  • 최대 재시도 횟수를 넘기게 되는 경우 예외를 발생시킨다.
final int MAX_RETRY = 100;
public Object someMethod() {
    int maxRetry = MAX_RETRY;
    while(maxRetry > 0) {
        try {
            ...
        } catch(SomeException e) {
            // 로그 출력. 정해진 시간만큼 대기한다.
        } finally {
            // 리소스 반납 및 정리 작업
        }
    }
    // 최대 재시도 횟수를 넘기면 직접 예외를 발생시킨다.
    throw new RetryFailedException();
}

예외 처리 회피

예외 처리를 직접 담당하지 않고 호출한 쪽으로 던져 회피하는 방법

  • 그래도 예외 처리의 필요성이 있다면 어느 정도는 처리하고 던지는 것이 좋다.
  • 긴밀하게 역할을 분담하고 있는 관가 아니라면 예외를 그냥 던지는 것은 무책임하다.
// 예시 1
public void add() throws SQLException {
    // ...생략
}

// 예시 2 
public void add() throws SQLException {
    try {
        // ... 생략
    } catch(SQLException e) {
        // 로그를 출력하고 다시 날린다!
        throw e;
    }
}

예외 전환

예외 회피와 비슷하게 메서드 밖으로 예외를 던지지만, 그냥 던지지 않고 적절한 예외로 전환해서 넘기는 방법

  • 조금 더 명확한 의미로 전달되기 위해 적합한 의미를 가진 예외로 변경한다.
  • 예외 처리를 단순하게 만들기 위해 포장(wrap) 할 수도 있다.
// 조금 더 명확한 예외로 던진다.
public void add(User user) throws DuplicateUserIdException, SQLException {
    try {
        // ...생략
    } catch(SQLException e) {
        if(e.getErrorCode() == MysqlErrorNumbers.ER_DUP_ENTRY) {
            throw DuplicateUserIdException();
        }
        else throw e;
    }
}

// 예외를 단순하게 포장한다.
public void someMethod() {
    try {
        // ...생략
    }
    catch(NamingException ne) {
        throw new EJBException(ne);
        }
    catch(SQLException se) {
        throw new EJBException(se);
        }
    catch(RemoteException re) {
        throw new EJBException(re);
        }
}

🙇🏻‍♀️ 레퍼런스

자바 예외 구분: Checked Exception, Unchecked Exception
[Java] Checked Exception vs Unchecked Exception 정리
자바 공부를 어떻게 하길래, "언체크드 예외 발생시 트랜잭션 롤백?"

0개의 댓글