본문 바로가기

기초 지식/Java

[Java] Checked Exception, Unchecked Exception

1. Checked Exception, Unchecked Exception이란

자바로 열심히 코딩을 하다보면 여러가지 Exception(예외)들을 만납니다. 실무에서뿐만 아니라 코딩테스트를 풀다가도 자주 만나는 Exception으로는 NullPointException, ArrayIndexOutOfBoundsException 등이 있습니다. 그렇다면 앞의 두 예시는 어떤 상황에서 발생할까요?

 

보통은 컴파일 시에는 발생하지 않습니다. 그랬다면 이미 알고 수정했을겁니다. 그렇다면 실행도중에 발생한 예외일겁니다. 그럼 Runtime 시점에 발생했으니 RuntimeException일겁니다. 이것들은 우리가 프로젝트를 실행할 때는 전혀 문제가 없습니다. 그래서 굳이 에러가 발생할 상황이 만들어지지 않는다면 체크할 필요가 없죠. 그래서 이것을 Unchecked Exception이라고 부릅니다. RuntimeException들을 상속받은 Exception들입니다.

 

그렇다면 반대로 Checked Exception은 뭘까요? Runtime 시점에 발생하지 않고 Compile 시점에 발생해서 무조건 체크해야하는 Exception들입니다. Checked Exception은 try catch를 사용하던 다른 방법을 사용하던 무조건 명시적으로 처이해주어야 합니다. 아래 그림에 있는 대표적인 예시로는 IOException이 있겠네요.

 

  • RuntimeException을 상속 여부는 두 Exception을 구분하는 요소

 

2. 어떠한 예외를 더 중시해야하나

그렇다면 어떠한 예외를 더 관심을 가지고 봐야할까요? 조금만 생각해보면 Unchecked Exception을 좀 더 신경 써야할 것 같습니다. Checked Exception은 개발과정에서 발견될 확률이 매우 높고 서비스를 사용하는 고객에게는 발생하기 쉽지 않습니다. 하지만 Unchecked Exception은 개발과정에서 테스트를 완벽하게 하지 않으면 언제든 발생할 수 있습니다.

3. 왜 Rollback을 해주지 않는걸까

위의 표에서 두 Exception의 트랜잭션 처리가 눈에 띕니다. 두 Exception 모두 Rollback에는 문제가 되지 않을 것 같은데 Unchecked는 처리해주고 Checked는 처리해주지 않네요. 왜 그런걸까요?

 

public void getFileWithName(String fileName){

    Path source = Paths.get("d:/tmp/text.txt");
    Path target = Paths.get("d:/tmp1/sample/text.txt");
    
    try {
    	Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
    } catch (IOException e) {
    	// source 파일이 없다면 source 경로에 빈파일을 만들고 다시 처리
    }
}

 

위의 코드 처럼 CheckedException이 발생하더라도 복구할 방법은 얼마든지 존재합니다. 게다가 예외처리를 무조건 해야하기도 하죠. 그렇다면 트랜잭션 롤백같은 복구는 왜 안해주는지 생각해보겠습니다. 여기서부터는 개인적인 의견이 들어가 있습니다.

 

Checked Exception을 롤백하지 않고 커밋하는 이유는 우리가 처리할 수 있기 때문인것 같습니다. CheckedException은 모든 경우를 명시적으로 처리하기 때문에 롤백 혹은 다른 처리를 진행하도록 충분히 기회가 주어진다고 볼 수 있습니다. 이에 반해 Runtime Exception은 대부분 개발자가 예상할 수 없는 순간에 발생합니다. 따라서 처리가 제대로 되어있지 않을 경우가 많습니다. 이 경우의 데이터 커밋은 치명적으로 다가올 수 있습니다. 따라서 롤백을 선택하게 되는 것 같습니다.  

 

추가적으로 스프링에서 트랜잭션 처리를 예외에 따라 보겠습니다.

  • Error, Unchecked Exception : 롤백
  • Checked Exception : 커밋

그리고 스프링에서는 Checked Exception을 Unchecked Exception으로 감싸서 외부로 던지도록 가이드가 되어있고 이 처럼 구성한다면 예외가 발생하는 메서드를 사용하는 부분에서는 예외처리를 굳이 하지 않아도 됩니다.

 

4. 어떻게 예외 처리하는 것이 좋은것일까

어떻게 예외처리를 하는 것이 Best라고 물어본다면 각자의 상황에 맞추는게 가장 좋은 것 같습니다. 하지만 어느정도 포괄적으로 보기 위해 위의 스프링의 예외처리 전략을 보면 좋을 것 같네요.

 

Checked -> Unchecked로 변경하는 전략은 try catch로 처리가 가능하고 이것의 이유가 명확하다면 try catch를 사용하는 것이 좋습니다. 하지만 그렇지 않은 경우가 더 많고 이때는 무의미한 try catch를 사용하는 것보다 Runtime Exception을 이용해 명확하게 메세지를 남기는 것이 더 좋은 방법입니다.

 

5. 정리

  • Checked Exception, Unchecked Exception의 주요 차이는 발생 시점과 Runtime Exception의 상속 유무다.
  • (주관적) Unchecked Exception을 Checked Exception보다 주의해야한다.
  • 스프링에서는 Checked Exception이 발생한 상황에서는 트랜잭션 커밋, 나머지는 트랜잭션 롤백한다.
  • 무의미한 try catch를 남발하는 것 보다는 Checked를 Unchecked로 감싸서 명확하게 메세지를 남기는 것이 더 좋다.

 

반응형