상세 컨텐츠

본문 제목

자바의 체크 예외 'catch' or 'throw'

JAVA

by 성찬우 2022. 10. 1. 16:54

본문

 

Exception Architecture

 

  • Object 결국 예외도 객체이다. 
  • Throwable 최상위 계층에 있는 예외이다. ExceptionError 로 나뉜다. 
  • Error 시스템 예외이다. 절대 이 예외를 잡아 처리하려고 해서는 안된다. Throwable 같은 곳에서도 catch 로 잡으면 자식까지도 잡을수 있기 때문에 Error도 같이 잡혀들어올 가능성이 있으므로 조심해야한다. 
  • Exception 은 체크 예외이다. 우리가 로직에서 핸들링이 가능한 실질적인 최상위 예외이다. 체크 예외는 컴파일러가 체크한다.
  • RuntimeException 언체크 예외인데 하위 계층까지 모두 "런타임 예외"라고도 불리운다. 

 

예외를 처리하는 2가지 규칙
  • 예외를 잡아서 처리하거나 던져야한다. 
  • 예외를 잡거나 던질 때 지정한 예외뿐만 아니라 그 예외의 자식들도 함께 처리된다.
    • Exception 을 잡거나 던지면 그 하위 예외들도 모두 잡거나 던질 수 있다.

하지만 계속해서 잡아 처리하지 못하고 던지는 상황이 계속된다면 시스템이 다운 된다. 

그렇기 때문에 웹어플리케이션(WAS)에서 해당 예외를 받아 처리하게 하는데

지정된 페이지를 보여주는 식으로 처리가 된다.  

 

 

체크 예외

Exception 및 그 하위 예외(RunTimeException 을 제외한)는 모두 컴파일러가 체크하는 체크 예외이다.

체크예외는 잡아 처리하거나 던져야한다 그렇지 않으면 컴파일 오류가 발생한다.

 

@Slf4j
public class CheckedTest {
//오류를 발생시키는 부분
    static class CheckedExceptionExample extends Exception{
        public CheckedExceptionExample(String message){
            super(message);
        }
    }

  //오류를 던지는 부분
    static class ExceptionThrowExample{
        public void errorThrow() throws CheckedExceptionExample {
            throw new CheckedExceptionExample("error message");
        }
    }
}

 

ExceptionThrowExample 에서 만든 errorThrow() 함수를 호출하면

throws CechkedExceptionExample로 컴파일시에 해당 부분을 확인 할 수 있도록 

설정가능하다. throws CechkedExceptionExample가 없으면 아마 오류가 발생할 것이다. 

 

그리고 이 오류를 또 다른 함수에서 호출하여 try-catch 문으로 잡을 수 있는데 

static class ExceptionCatchExample{
    ExceptionThrowExample repository = new ExceptionThrowExample();

    public void errorCatch(){
        try {
            repository.errorThrow();
        } catch (CheckedExceptionExample e) {
            log.info("this is error message = {}", e.getMessage(), e);
        }
    }
}

다음과 같이 던지는 부분을 받아서 try-catch 로 CheckedExceptionExample 객체 에러를 받아 처리했다. 

 

그래서 던지는 거랑 받는 거랑 뭐가 다른데?

이 부분에 대해서는 Test code로 확인이 가능하다. 

@Slf4j
class CheckedExceptionTest {

    static class CheckedExceptionExample extends Exception{
        public CheckedExceptionExample(String message){
            super(message);
        }
    }

    static class ExceptionCatchExample{
        CheckedTest.ExceptionThrowExample repository = new CheckedTest.ExceptionThrowExample();
        public void errorCatch(){
            try {
                repository.errorThrow();
            } catch (CheckedExceptionTest.CheckedExceptionExample e) {
                log.info("this is error message = {}", e.getMessage(), e);
            }
        }
    }

    static class ExceptionThrowExample{
        public void errorThrow() throws CheckedTest.CheckedExceptionExample {
            throw new CheckedTest.CheckedExceptionExample("error message");
        }
    }


}

이 코드를 그대로 들고 가서 @Test를 생성해볼건데

 

@Test
void checkedError_catch(){
    ExceptionCatchExample exceptionCatchExample = new ExceptionCatchExample();
    exceptionCatchExample.errorCatch();
}

해당 코드는 에러를 잡아서 log를 받아내는 부분이다. 실행을 해보면 

윗줄에 log.info 가 나오고 마지막에 stackTrace로 인한 오류 정보가 나오고 Test가 성공한다. 

 

 

하지만 던지는 부분은 어떻게 될까?

 

@Test
void checkedError_throw() throws CheckedExceptionTest.CheckedExceptionExample {
    ExceptionThrowExample exceptionThrowExample = new ExceptionThrowExample();
    exceptionThrowExample.errorThrow();
}

역시나 throws로 해당 오류를 받아서 사용한다. 하지만 이 테스트는 실패할 것이다. 

error message만 출력이 되고 실패하게 된다. 

 

이 부분에 대해서는 오류가 터질 것이라고 Assertions 를 넣어줘야 테스트가 성공한다. 

 

@Test
void checkedError_throw() throws CheckedTest.CheckedExceptionExample {
    ExceptionThrowExample exceptionThrowExample = new ExceptionThrowExample();
    Assertions.assertThatThrownBy(()-> exceptionThrowExample.errorThrow())
            .                isInstanceOf(CheckedTest.CheckedExceptionExample.class);
}

이렇게 함수를 호출 했을 때 isInstanceOf(errorName.class)로 넘겨줘야한다.

이렇게 테스트를 통과시킬수 있다. 

 

 

만약 오류를 Exception 으로 그냥 퉁 쳐버리면 어떻게 될까?

 

static class ExceptionCatchExample{
        CheckedTest.ExceptionThrowExample repository = new CheckedTest.ExceptionThrowExample();
        public void errorCatch(){
            try {
                repository.errorThrow();
            } catch (ExceptionCatchExample.CheckedExceptionExample e) {
                log.info("this is error message = {}", e.getMessage(), e);
            }
        }
    }

아까 이부분에서 ExceptionCatchExample.CheckedExceptionExample 로 받아서 사용했는데 

 

이거를 그냥 Exception 으로 catch 하면 어떻게 될까?

 

static class ExceptionCatchExample{
        CheckedTest.ExceptionThrowExample repository = new CheckedTest.ExceptionThrowExample();

        public void errorCatch(){
            try {
                repository.errorThrow();
//            } catch (CheckedTest.CheckedExceptionExample e) {
            } catch (Exception e) {
                log.info("this is error message = {}", e.getMessage(), e);
            }
        }
    }

 

바로 이렇게 바꿔서 한번 Test를 실행해보면 

 

여전히 Error를 잡아 처리하는 것을 확인 할 수 있다. 

근데 이제 문제는 이렇게 하면 CheckedExceptionExample error'만' 잡을 수 없게된다... 모든 에러를 잡아버린다는 것

물론 컴파일시 확인 해주는 throws 뒤에 Exception도 그냥 Exception 으로 처리가 가능하다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

'JAVA' 카테고리의 다른 글

Map  (0) 2022.10.18
[체크,언체크] 예외의 활용  (0) 2022.10.04
언체크-런타임 예외  (0) 2022.10.03
java 8 : stream  (0) 2022.09.14

관련글 더보기

댓글 영역