java

Checked Exception vs UncheckedException

kivv00ng 2022. 12. 19. 14:53

 

에러와 예외

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

그러나 에러는 시스템에 무엇인가 비정상적인 상황이 발생한 경우를 말한다. 주로 자바 가상 머신에서 발생하는 것이며, 예외와 반대로 이를 애플리케이션 코드에서 잡을 수 없다. 에러의 예시로는 OutOfMemoryError, ThreadDeath, StackOverflowError 등이 있다.

자바 예외 구분

checked vs unchecked

이번 글의 제목처럼 Exception Checked Exception Unchecked Exception으로 구분할  있다.

간단하게 RuntimeException 상속하지 않는 클래스 Checked Exception이고,  상속한 클래스는 Unchecked Exception으로

분류할  있다.

 

checkedException: 이름 그대로 컴파일시에 체크되는 예외로,명시적인 예외처리를 실행 전에 강제한다.

uncheckedException: checked와 반대로 컴파일시 체크되지않고 런타임시 발생하는 예외로, 명시적인 예외처리가 필요 없다.

*명시적인 예외처리: try-catch or throw를 말한다. 

예외처리 방식

  • 예외복구 : 예외상황을 파악하고 해당 예외에 따른 문제를 해결한 뒤 정상 상태로 돌려 놓는 방법 
  • 예외처리회피: throws를 이용하여 호출한 쪽으로 예외처리를 미루는 방식
  • 예외전환: try-catch로 받은 뒤 적절한 예외를 다시 throw 해주는 방식

DB와 입출력에서 발생하는 checkedException처리

나는 아래의 피드백 받은 코드에서는 발생하는 checkedException을 회피하고 전부 던졌다.(변경 전)

 public Voucher findVoucherV0(long voucherId) throws IOException {
        File csv = new File(path);
        String line;
        BufferedReader br = new BufferedReader(new FileReader(csv));
        while ((line = br.readLine()) != null) {
            if (matchId(line, voucherId)) {
                return stringToVoucher(line);
            }
        }
        throw new NotFoundVoucherException();
    }

 

이는 예외를 처리하는 prensentation계층까지 해당 메소드에 영향을 받는 모든 클래스들은 전부 IOException을 의존해야 해서 유지보수성에 좋지 못했다.

또 호출하는 쪽에서 실제 구현 코드가 inputOut관련된 로직이 짜여져 있는 것을 대략적으로 추측이 가능하기 때문에 캡슐화적인 측면에서도 좋지 못했다. 따라서 나는 두개의 문제점을 해결하고자 코드를 리팩토링 했다.

 public Voucher findVoucher(long voucherId) {
        File csv = new File(path);
        String line;
        try (BufferedReader br = new BufferedReader(new FileReader(csv));) {
            while ((line = br.readLine()) != null) {
                if (matchId(line, voucherId)) {
                    return stringToVoucher(line);
                }
            }
        } catch (FileNotFoundException e) {
            throw new FileNotFoundCustomException();
        } catch (IOException e) {
            throw new FileInOutException();
        }
        throw new NotFoundVoucherException();
    }

try-catch로 해당 CheckedException을 잡은 뒤, 새로만든 UncheckedException으로 예외를 전환하여 주었다.

이렇게 되니 해당 메소드에 영향을 받는 클래스들에서 파일 입출력에대한 예외를 의존하지 않아도 되었고, 또 캡슐화까지 보장할 수 있었다.

김영한님의 강의를 찾아보니 비슷한 맥락으로 CheckedExcpetion을 Unchecked Exception으로 전환해주는 것을  확인했다.

(계층 누수 멈춰!) 트랜잭션 관련해서는 Rollback에 대한 이유도 존재했다.