체크 예외는 말 그대로 발생한 예외를 잡아서(catch) 체크한 후에 해당 예외를 복구 하든가 아니면 회피 하든가 등의 어떤 구체적인 처리를 해야 하는 예외다.
Java에서 흔히 볼 수 있는 대표적인 체크 예외로는 ClassNotFoundException
등을 들 수 있다.
반면에 언체크 예외는 예외를 잡아서(catch) 해당 예외에 대한 어떤 처리를 할 필요가 없는 예외를 의미한다. 따라서 언체크 예외는 명시적으로 잡아서(catch) 어떤 처리를 할 필요가 없다.
대표적인 언체크 예외로는 NullPointerException
, ArrayIndexOutOfBoundsException
등이 있다.
흔히 개발자가 코드를 잘못 작성해서 발생하는 이런 오류들은 모두 RuntimeException
을 상속한 예외들이다.
@Service
public class MemberService {
...
...
public Member findMember(long memberId) {
// TODO should business logic
// (1)
throw new RuntimeException("Not found member");
}
...
...
}
@RestControllerAdvice
public class GlobalExceptionAdvice {
...
...
// (1)
@ExceptionHandler
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleResourceNotFoundException(RuntimeException e) {
System.out.println(e.getMessage());
return null;
}
}
import lombok.Getter;
public enum ExceptionCode {
MEMBER_NOT_FOUND(404, "Member Not Found");
@Getter
private int status;
@Getter
private String message;
ExceptionCode(int status, String message) {
this.status = status;
this.message = message;
}
}
서비스 계층에서 던질 Custom Exception에 사용할 ExceptionCode를 enum으로 정의한다.
이처럼 ExceptionCode를 enum으로 정의하면 비즈니스 로직에서 발생하는 다양한 유형의 예외를 enum에 추가해서 사용할 수 있다.
BusinessLogicException
이라는 Custom Exception을 정의import lombok.Getter;
public class BusinessLogicException extends RuntimeException {
@Getter
private ExceptionCode exceptionCode;
public BusinessLogicException(ExceptionCode exceptionCode) {
super(exceptionCode.getMessage());
this.exceptionCode = exceptionCode;
}
}
BusinessLogicException
은 RuntimeException을 상속하고 있으며 ExceptionCode를 멤버 변수로 지정하여 생성자를 통해서 조금 더 구체적인 예외 정보들을 제공해줄 수 있다.
그리고 상위 클래스인 RuntimeException의 생성자(super)로 예외 메시지를 전달해준다.
BusinessLogicException
은 서비스 계층에서 개발자가 의도적으로 예외를 던져야 하는 다양한 상황에서 ExceptionCode 정보만 바꿔가며 던질 수 있다.
@Service
public class MemberService {
...
...
public Member findMember(long memberId) {
// TODO should business logic
// (1)
throw new BusinessLogicException(ExceptionCode.MEMBER_NOT_FOUND);
}
...
...
}
@RestControllerAdvice
public class GlobalExceptionAdvice {
...
...
@ExceptionHandler
public ResponseEntity handleBusinessLogicException(BusinessLogicException e) {
System.out.println(e.getExceptionCode().getStatus());
System.out.println(e.getMessage());
return new ResponseEntity<>(HttpStatus.valueOf(e.getExceptionCode().getStatus()));
}
}
@RestControllerAdvice에서 @ResponseStatus 와 ResponseEntity 의 사용 방법
한가지 유형으로 고정된 예외를 처리할 경우에는
@ResponseStatus
로 HttpStatus를 지정해서 사용하면 되고, BusinessLogicException 처럼 다양한 유형의 Custom Exception을 처리하고자 할 경우에는ResponseEntity
를 사용하면 된다.
체크 예외(Checked Exception)는 예외를 잡아서(catch) 체크한 후에 해당 예외를 복구 하든가 아니면 회피를 하든가 등의 어떤 구체적인 처리를 해야하는 예외이다.
언체크 예외(Unchecked Exception)는 예외를 잡아서(catch) 해당 예외에 대한 어떤 처리를 할 필요가 없는 예외를 의미한다.
RuntimeException을 상속한 예외는 모두 언체크 예외(Unchked Exception)이다.
RuntimeException을 상속해서 개발자가 직접 사용자 정의 예외(Custom Exception)를 만들 수 있다.
사용자 정의 예외(Custom Exception)를 정의해서 서비스 계층의 비즈니스 로직에서 발생하는 다양한 예외를 던질 수 있고, 던져진 예외는 Exception Advice에서 처리할 수 있다.
@ResponseStatus
애너테이션은 고정된 예외를 처리할 경우에 사용할 수 있다.
HttpStatus가 동적으로 변경되는 경우에는 ResponseEntity
를 사용한다.