728x90
Exception과 그 하위 예외는 모두 컴파일러가 체크하는 체크 예외이다. 단 RuntimeException 은 예외로 한다.
체크 예외는 잡아서 처리하거나, 또는 밖으로 던지도록 선언해야 한다. 그렇지 않으면 컴파일 오류가 발생한다.
@Slf4j
public class CheckedTest {
@Test
public void checked_catch() {
Service service = new Service();
service.callCatch();
}
@Test
public 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 { //잡거나 던져야 하기 떄문에 던진다.
throw new MyCheckedException("ex");
}
}
}
MyCheckedException
- MyCheckedException 는 Exception을 상속받았다. Exception을 상속받으면 체크 예외가 된다.
- 참고로 RuntimeException 을 상속받으면 언체크 예외가 된다. 이런 규칙은 자바 언어에서 문법으로 정한 것이다.
- 예외가 제공하는 여러가지 기본 기능이 있는데, 그중에 오류 메시지를 보관하는 기능도 있다. 예제에서 보는 것처럼 생성자를 통해서 해당 기능을 그대로 사용하면 편리하다
checked_catch()
- service.callCatch() 에서 예외를 처리했기 때문에 테스트 메서드까지 예외가 올라오지 않는다.
- Repository.call()에서 MyUncheckedException 예외가 발생하고, 그 예외를 Service.callCatch()에서 잡는 것을 확인할 수 있다.
- 로그를 남길 때 로그의 마지막 인수에 예외 객체를 전달해주면 로그가 해당 예외의 스택 트레이스를 추가로 출력해준다.
- log.info("예외 처리, message={}", e.getMessage(), e); //여기서 마지막에 있는 e 부분이다
- 체크 예외를 잡아서 처리하려면 catch(..) 를 사용해서 예외를 잡으면 된다.
- 여기서는 MyCheckedException 예외를 잡아서 처리한다
- catch에 MyCheckedException의 상위 타입인 Exception을 적어주어도 MyCheckedException을 잡을 수 있다.
- catch 에 예외를 지정하면 해당 예외와 그 하위 타입 예외를 모두 잡아준다.
- 물론 정확하게 MyCheckedException 만 잡고 싶다면 catch에 MyCheckedException을 적어주어야 한다
checked_throw()
- service.callThrow() 에서 예외를 처리하지 않고, 밖으로 던졌기 때문에 예외가 테스트 메서드까지 올라온다.
- 테스트에서는 기대한 것 처럼 MyCheckedException 예외가 던져지면 성공으로 처리한다.
- 체크 예외를 처리할 수 없을 때는 method() throws 예외 을 사용해서 밖으로 던질 예외를 필수로 지정해주어야 한다. 여기서는 MyCheckedException을 밖으로 던지도록 지정해주었다.
- throws를 지정하지 않으면 컴파일 오류가 발생한다.
- Unhandled exception: hello.jdbc.exception.basic.CheckedTest.MyCheckedException
- 체크 예외의 경우 예외를 잡아서 처리하거나 또는 throws를 지정해서 예외를 밖으로 던진다는 선언을 필수로 해주어야 한다
- throws에 MyCheckedException의 상위 타입인 Exception을 적어주어도 MyCheckedException을 던질 수 있다.
- throws에 지정한 타입과 그 하위 타입 예외를 밖으로 던진다.
- 물론 정확하게 MyCheckedException 만 밖으로 던지고 싶다면 throws에 MyCheckedException을 적어주어야 한다.
체크 예외의 장단점
체크 예외는 예외를 잡아서 처리할 수 없을 때, 예외를 밖으로 던지는 throws 예외 를 필수로 선언해야 한다. 그렇지 않으면 컴파일 오류가 발생한다. 이것 때문에 장점과 단점이 동시에 존재한다.
- 장점: 개발자가 실수로 예외를 누락하지 않도록 컴파일러를 통해 문제를 잡아주는 훌륭한 안전 장치이다.
- 단점: 하지만 실제로는 개발자가 모든 체크 예외를 반드시 잡거나 던지도록 처리해야 하기 때문에, 너무 번거로운 일이 된다. 크게 신경 쓰고 싶지 않은 예외까지 모두 챙겨야 한다. 추가로 의존관계에 따른 단점도 있는데 이 부분은 뒤에서 설명하겠다
728x90
'스프링 DB 1편(데이터 접근 핵심 원리)' 카테고리의 다른 글
| Ch05. 자바 예외 이해 - 체크 예외 활용 (0) | 2022.04.30 |
|---|---|
| Ch05. 자바 예외 이해 - 언체크 예외 기본 이해 (0) | 2022.04.30 |
| Ch05. 자바 예외 이해 - 예외 계층 & 예외 기본 규칙 (0) | 2022.04.30 |
| Ch04. 스프링과 문제 해결(트랜잭션) - 스프링 부트의 자동 리소스 등록 (0) | 2022.04.27 |
| Ch04. 스프링과 문제 해결(트랜잭션) - 트랜잭션 문제 해결(트랜잭션 AOP 정리) (0) | 2022.04.27 |