본문 바로가기
Java & 스프링/Java

[Java] 자바의 예외 - Exception, RuntimeException 그리고 Error

by hjhello423 2019. 11. 5.

자바의 Error, Exception에 대해 알아보려 한다.

지금부터 볼 내용은 포스팅 가장 아래의 레퍼런스 링크를 참조해서 읽어보면 좋겠다.

 

 


 

출처 : https://nesoy.github.io/articles/2018-05/Java-Exception

일단 Error와 Exception의 차이에 대해 알아보자.

 

 

Throwable class

Throwable 클래스는 Java 언어의 모든 오류 및 예외의 슈퍼 클래스이다.

이 클래스의 인스턴스(또는 그 서브 클래스 중 하나)인 객체만 Java Virtual Machine에 의해 발생되거나 Java throw 문에 의해 발생될 수 있다.

예외의 compile-time checking을 위해, RuntimeException 또는 Error의 서브 클래스가 아닌 Throwable 및 Throwable의 서브 클래스는 Checked 예외로 간주된다.

Error class

Error는 Throwable의 하위 클래스로서, 응용 프로그램의 심각한 문제를 나타내는 클래스이다.

시스템에 비정상적인 상황이 생겼을 때 발생한다. (시스템 레벨에서 발생한다.)

이러한 오류는 대부분 비정상적인 상태이다. "정상"조건이지만 ThreadDeath 오류는 대부분의 응용 프로그램이 이를 잡아 내려고 하지 않기 때문에 Error의 하위 클래스이기도 하다.
Error의 서브 클래스를 throws 선언할 필요는 없다.

Error 및 해당 서브 클래스는 예외 컴파일 시간 검사를 위해 unchecked Exception으로 간주된다.

Exception class

Exception 클래스와 그 subclass는 응용 프로그램이 catch 할 수 있는 조건을 나타내는 Throwable 형식이다.

Exception 클래스와 RuntimeException의 subclass가 아닌 서브 클래스는 checked exception이다.

직접 구현하여 개발자가 비즈니스 로직에 맞게 생성 가능하다.

수많은 subclass가 있으므로 꼭 reference를 확인해 보자.

RuntimeException

RuntimeException은 Java Virtual Machine의 정상적인 작동 중에 발생할 수 있는 예외의 슈퍼 클래스이다.
RuntimeException 및 해당 서브 클래스는 unchecked exception이다. unchecked exception은 메서드 또는 생성자의 실행에 의해 발생한다.

메서드 또는 생성자 경계 외부로 전파될 수 있는 경우 메서드 또는 생성자의 throws 절에서 선언될 필요가 없다.

 


출처 : http://www.nextree.co.kr/p3239/

 

checked/unchecked exception의 가장 큰 차이는 처리 방식이다.

checked exception이 발생할 가능성이 있다면 throws로 상위로 처리를 위임하거나 try-catch문으로 처리해야 한다.

반면 unchecked exception은 

 

checked exception

- 반드시 예외 처리를 해야 한다. (try~catch를 통해)

- 컴파일 단계에서 확인 가능하다.

- 예외 발생 시 트랜잭션 roll back 하지 않는다.

- RuntimeException을 제외한 Exception의 하위 클래스

unchecked exception

- 명시적 예외 처리를 강제하지 않는다.

- 실행 단계에서 확인 가능하다.

- 예외 발생 시 트랜잭션 roll back 한다.

- RuntimeException의 하위 클래스

 

 


 

대표적인 Exception

  • IllegalArgumentException : 매개변수가 의도하지 않은 상황을 유발할 때
  • IllegalStateException : 메서드를 호출하기 위한 상태가 아닐 때
  • NullPointerException : 변수 값이 null 일 때 사용하는 경우 
  • IndexOutOfBoundsException : 인덱스 매개 변수 값이 범위를 벗어날 때
  • ArithmeticException : 산술적인 연산에 오류가 있을 때
  • IOException : 
  • FileNotFoundException :
  • ArrayIndexOutOfBoundsExcetion

 


예외 처리 방법

예외 복구

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

예외가 처리됐으면 기능적으로는 사용자에게 예외상황으로 비쳐도 애플리케이션에서는 정상적으로 설계된 흐름을 따라 진행돼야 한다.

정해진 횟수만큼 재시도하고 횟수 이상으로 실패할 경우 예외 복구를 포기한다.

int maxretry = MAX_RETRY;  
while(maxretry -- > 0) {  
    try {
        ... 				// 예외가 발생할 가능성이 있는 시도
        return; 			// 작업성공시 리턴
    }
    catch (SomeException e) {
        // 로그 출력. 정해진 시간만큼 대기
    } 
    finally {
        // 리소스 반납 및 정리 작업
    }
}
throw new RetryFailedException(); // 최대 재시도 횟수를 넘기면 직접 예외 발생

<토비의 스프링 참조>

예외처리 회피

예외처리를 자신이 담당하지 않고 자신을 호출한 쪽으로 던져버리는 것이다.

throws 문으로 선언해서 예외가 발생하면 알아서 던져지게 하거나 catch 문으로 예외를 잡은 후에 log를 남기고 다시 예외를 던지는(rethrow)것이다.

public void add() throws SQLException {  
    // JDBC API
}

<토비의 스프링 참조>

JdbcTemplate를 예로 들어 보자 JdbcTemplate에서 ResultSet이나 PreparedStatement 등을 이용해서 작업하다 발생하는 SQLException을 자신이 처리하지 않고 템플릿으로 던져버린다. 콜백 오브젝트의 메서드는 모두 throws SQLException이 붙어있는데 Exception을 처리하는 일은 콜백 오브젝트의 역할이 아니라고 보기 때문이다.

예외를 회피하는 것은 예외를 복구하는 것보다 의도가 분명해야 한다.

반드시 다른 관계있는 오브젝트나 자신을 사용하는 쪽에서 예외를 다루게 해야 한다.

예외 전환

예외 회피와 비슷하게 예외를 복구해서 정상적인 상태로 돌릴 수 없기 때문에 예외 메서드를 밖으로 던지는 방법이다.

어떤 예외 상황에 대해 의미가 좀 더 명확한 예외로 재정의 하여 throws 한다.

예를 들어 user등록 로직에서 id 중복으로 인한 SQLException 발생 시에 예외를 DuplicateUserIdException과 같이 의미를 정확하게 전달해주는 방법이다.

public void add(User user) throws DuplicateUserIdException, SQLException {
    try {
        // JDBC를 이용해 user 정보를 DB에 추가
    }
    catch(SQLException e) {
        if(e.getErrorCode() == MysqlErrorNumbers.ER_DUP_ENTRY)
            throws DuplicateUserIdException(); // ErrorCode가 MySQL의 Duplicate Entry(1062)이면 예외 전환
        else
            throwse; // SQLException 그대로 
    }
}

<토비의 스프링 참조>

 

보통 중첩 예외를 만들어서 예외를 던지는 것이 좋다.

중첩 예외란 전환하려는 예외(DuplicateUserIdException)에 원래의 예외(SQLException)를 담는 것을 말한다.

catch(SQLException e) {  
   ...
   throw DuplicateUserIdException(e);
}


catch(SQLException e) {  
   ...
   throw DuplicateUserIdException().initCause(e);
}


<토비의 스프링 참조>

 

 


링크

 

반응형

댓글