-
[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 불일치 예외)
반응형'프로그래밍 언어 > JAVA' 카테고리의 다른 글
[JAVA] ArrayList 값 출력하기 ( 인덱스, forEach, 확장 for문) (0) 2023.04.10 [ch12 자바 지네릭스] 개념, 다형성, Generic 타입 클래스 (0) 2023.02.27 [JAVA] ArrayList 초기화하는 방법 4가지 (0) 2023.01.27 [JAVA] Scanner 와 BufferedReader (0) 2023.01.26 [JDK] 설치 후 환경변수 설정 (path, JAVA_HOME) (0) 2022.12.07