ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JAVA] 자바 예외처리 이해하기
    프로그래밍 언어/JAVA 2023. 2. 15. 12:57

     

     

    📑 자바 예외 계층

     

     

    🎈 Object : 예외도 객체이다. 모든 객체의 최상위 부모는 Object

     

    🎈 Throwable : 최상위 예외이다. 하위에 Exception과 Error가 있다.

     

    🎈 Error : 메모리 부족이나 심각한 시스템 오류와 같이 애플리케이션에서 복구 불가능한 시스템 예외이다. 애플리케이션 개발자는 이 예외를 잡으려고 해서는 안된다. 

    상위 예외를 catch로 잡으면 그 하위 예외까지 함께 잡는다. 따라서 애플리케이션 로직에서는 Throwable로 잡으면 안되는데, 앞서 이야기한 Error 예외도 잡을 수 있기 때문이다. 애플리케이션 로직은 이런 이유로 Exception 부터 필요한 예외로 생각하고 잡으면 된다. 

     

    🎈 Exception : 체크 예외

    애플리케이션 로직에 사용할 수 있는 실질적인 최상위 예외이다.

    Exception과 그 하위 예외는 모두 컴파일러가 체크하는 체크 예외이다. 단 RuntimeException은 예외로 한다.

     

    🎈 RuntimeException : 언체크 예외, 런타임 예외

    컴파일러가 체크하지 않는 언체크 예외이다. RuntimeException 이름에 따라서 RuntimeException과 그 하위 언체크 예외를 런타임 에러라고 많이 부른다. 

     

     

     


     

    📑 예외 처리 기본 규칙

     

    예외는 잡아서 처리하거나, 처리할 수 없으면 밖으로 던져야한다. 

     

     

     

    📑 체크 예외 예제 

     

     

     

     

    위의 코드를 살펴보면 예외를 던지고 있다. 이렇게 던질때는 extends로 밖으로 던지는 걸 선언해야한다. 아님 빨간줄 뜬다. 

     

     

     

    아래 코드는 예외를 잡아서 try~catch로 처리하는 것. 

     

     

     

     


     

    예외를 던지는 테스트를 진행할때 이렇게 아래 코드처럼 짜게 되면 예외가 발생했을 때 에러를 터뜨리기 때문에 아래 주석처리한 코드처럼 만약 에러가 발생하면 에러 대신에 MyCheckedException.class를 호출해줘라는 코드로 작성해야 한다. 

     

     

     

     

    package hello.jdbc.exception.basic;
    
    import lombok.extern.slf4j.Slf4j;
    import org.assertj.core.api.Assertions;
    import org.junit.jupiter.api.Test;
    
    @Slf4j
    public class CheckedTest {
    
    
        @Test
        void checked_catch(){
            Service service = new Service();
            service.callCatch();
        }
    
        @Test
        void checked_throw(){
            Service service = new Service();
            Assertions.assertThatThrownBy(()->service.callThrow()).isInstanceOf(MyCheckedException.class);
        }
    
    
        /**
         * Exception을 상속받은 예외는 체크 예외가 된다.
         */
        static class MyCheckedException extends Exception{
            //컴파일러가 체크하는 체크 예외
    
            public MyCheckedException(String message) {
                super(message);
            }
        }
    
        /**
         * checked 예외는
         * 예외를 잡아서 처리하거나, 던지거나 둘중 하나를 필수로 선택해야한다.
         */
        static class Service {
            Repository repository = new Repository();
            /**
             * 예외를 잡아서 처리하는 코드
             * */
            public void callCatch()  {
                try {
                    repository.call();
                } catch (MyCheckedException e) {
                    log.info("예외 처리, message={}", e.getMessage(),e);
                }
    
            }
    
            /**
             * 체크 예외를 밖으로 던지는 코드
             * 체크 예외는 예외를 잡지 않고 밖으로 던지려면 throws 예외를 메서드에  필수로 선언해야한다.
             * @throws MyCheckedException
             */
            public void callThrow() throws MyCheckedException {
                repository.call();
            }
        }
    
        static class Repository{
            public void call() throws MyCheckedException {
                //exception을 터뜨리는다.
                throw new MyCheckedException("ex"); //던지려면 무조건 throws로 선언을 해야된다.
            }
        }
    }

     

     

     

     

     

     

    📑 언체크 예외 예제

     

    언체크 예외는 체크 예외와 기본적으로 동일하다. 차이가 있다면 예외를 던지는 throws를 선언하지 않고, 생략할 수 있다는 것! 이 경우 자동으로 예외를 던진다. 

     

    package hello.jdbc.exception.basic;
    
    import lombok.extern.slf4j.Slf4j;
    import org.assertj.core.api.Assertions;
    import org.junit.jupiter.api.Test;
    
    @Slf4j
    public class UncheckedTest {
    
    
        @Test
        void unchecked_catch(){
            Service service = new Service();
            service.callCatch();
        }
    
        @Test
        void unchecked_throw(){
            Service service = new Service();
            Assertions.assertThatThrownBy(()->service.callThrow()).isInstanceOf(MyUncheckedException.class);
    
        }
    
    
    
        /**
         * RuntimeException을 상속받은 예외는 언체크 예외가 된다.
         */
        static class MyUncheckedException extends  RuntimeException{
            public MyUncheckedException(String message) {
                super(message);
            }
        }
    
        /**
         * Uncehced 예외는 예외를 잡거나, 던지지 않아도 된다.
         * 예외를 잡지 않으면 자동으로 밖으로 던진다.
         */
        static class Service{
            Repository repository = new Repository();
    
            /**
             * 필요한 경우 예외를 잡아서 처리하면 된다.
             */
            public void callCatch(){
                try{
                    repository.call();
                }catch (MyUncheckedException e){
                    log.info("예외 처리, message={}", e.getMessage(),e);
                }
            }
    
            /**
             * 예외를 잡지 않아도 된다. 자연스럽게 상위로 넘어간다.
             * 체크 예외와 다르게 throws 예외 선언을 하지 않아도 된다.
             */
            public void callThrow(){
                repository.call();
            }
        }
    
    
    
        static class Repository{
            public void call(){
                throw new MyUncheckedException("ex");
            }
        }
    }

     

     

     

    📑 체크 VS 언체크 언제 사용할까? 

     

    🎈 기본적으로 언체크(런타임) 예외를 사용하자

     

    🎈 체크 예외는 비즈니스 로직상 의도적으로 던지는 예외만 사용하자. 이 경우 해당 예외를 잡아서 반드시 처리해야 하는 문제일 때만 체크 예외를 사용한다.  (ex. 계좌 이체 실패 예외, 결제시 포인트 부족 예외, 로그인 ID, PW 불일치 예외) 

     

     

     

     

    반응형

    댓글

Designed by Tistory.