[자바 라이브 스터디] 9주차 - 예외 처리
•
목표) 자바의 예외 처리에 대해 학습하세요.
1. Exception과 Error의 차이는?
•
프로그램 에러
◦
정의) 프로그램 실행 중 오작동을 하거나 비정상적으로 종료되게 하는 원인
◦
종류) 발생 시점에 따라 구분
▪
컴파일 에러 : 컴파일 시 발생
▪
런타임 에러 : 실행 시 발생
▪
논리적 에러 : 실행은 되지만, 의도와 다르게 동작
•
예외와 에러
◦
정의) 자바는 런타임 에러를 예외와 에러 두 가지로 구분함
◦
종류)
▪
예외(Exception)
•
정의) 프로그램 코드에 의해 수습될 수 있는 다소 미약한 오류
▪
에러(Error)
•
정의) 프로그램 코드에 의해 수습될 수 없는 심각한 오류
•
예시) 메모리 부족, 스택오버플로우
2. 자바가 제공하는 예외 계층 구조
•
정의) 자바에선 예외와 에러를 클래스로 정의함
◦
•
특징)
◦
모든 클래스의 조상은 Object 클래스이므로 예외(Exception)와 에러(Error) 클래스 역시 Object 클래스의 자손들임
3. RuntimeException과 RE가 아닌 것의 차이는?
•
정의) RuntimeException 클래스와 그 자손 클래스들을 RuntimeException 클래스들이라 하고, RuntimeException클래스들을 제외한 나머지 클래스들을 Exception 클래스들 이라 하자.
◦
Exception 클래스와 RuntimeException클래스 중심의 상속 계층도
•
차이점)
◦
RuntimeException 클래스들
▪
정의) 프로그래머의 실수로 발생하는 예외
▪
예시) ArrayIndexOutOfBoundException, NullPointerException, ClassCastException, ArithmeticException
◦
Exception 클래스들
▪
정의) 사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외
▪
예시) FileNotFOundException, ClassNotFoundException, DataFormatException
4. 자바에서 예외 처리 방법 (try, catch, throw, throws, finally)
•
정의) 프로그램 실행 시 발생할 수 있는 예외에 대비한 코드 작성
•
목적) 프로그램의 비정상 종료를 막고, 정상적인 실행 상태를 유지하게 함
◦
발생한 예외 처리 못하면, 프로그램은 비정상적으로 종료되며 처리되지 못한 예외는 JVM의 예외처리기(UncaughtExceptionHandler)가 받아서 예외의 원인을 화면에 출력함
•
방법)
◦
try-catch문 이용
▪
구조)
try {
// 예외가 발생할 가능성이 있는 코드
} catch (Exception1 e1) {
// Exception1이 발생했을 때, 이를 처리하기 위한 코드
} catch (Exception2 e2) {
// Exception2가 발생했을 때, 이를 처리하기 위한 코드
} catch (ExceptionN eN) {
// ExceptionN이 발생했을 때, 이를 처리하기 위한 코드
}
Java
복사
▪
특징)
•
예외의 종류와 일치하는 단 한 개의 catch 블럭만 수행됨
•
발생한 예외의 종류와 일치하는 catch 블럭이 없으면 예외는 처리되지 않음
•
괄호 생략 불가함
•
finally 블럭을 덧붙여 예외의 발생 여부에 상관 없이 실행되어야 할 코드 포함시킬 수 있음
◦
실행 순서는 예외가 발생한 경우엔 try → catch → finally 순, 예외가 발생하지 않은 경우엔 try → finally 순
◦
try-with-resources문 이용
▪
구조)
try (
// 여기서 할당 받은 자원은 블록 수행 이후 자동으로 반환됨
) {
// 예외가 발생할 가능성이 있는 코드
} catch (Exception e) {
// Exception 처리
}
Java
복사
▪
특징)
•
try-catch문의 변형으로 JDK1.7부터 추가됨
•
자원 해제를 자동으로 해줌
◦
단, 모든 객체가 자동으로 반환되는 것은 아니고 AutoCloseable 인터페이스를 구현한 클래스만 자동으로 반환됨
•
입출력과 관련된 클래스 사용할 때 유용함
◦
원래) finally 구문 사용
public static void main(String args[]) throws IOException {
FileInputStream is = null;
BufferedInputStream bis = null;
try {
is = new FileInputStream("file.txt");
bis = new BufferedInputStream(is);
//... do something
} catch (IOException e) {
// 에러처리
} finally {
// 어떤 경우에도 반드시 자원을 닫아야함
if (is != null) is.close();
if (bis != null) bis.close();
}
}
Java
복사
◦
변경) try-with-resources 구문 이용
public static void main(String args[]) {
try (
FileInputStream is = new FileInputStream("file.txt");
BufferedInputStream bis = new BufferedInputStream(is)
) {
//... do something
} catch (IOException e) {
// 에러처리
}
}
Java
복사
◦
메서드에 예외 선언
▪
구조)
void method() throws Exception1, Exception2 ... ExceptionN {
// 메서드의 내용
}
Java
복사
5. 커스텀한 예외 만드는 방법
•
평소에 아래와 같은 방식으로 만듦
◦
ErrorCode Enum
@Getter
@AllArgsConstructor
public enum ErrorCode {
// 공통 예외
BAD_REQUEST_PARAM(HttpStatus.BAD_REQUEST, "잘못된 요청입니다."),
// USER 예외
NOT_FOUND_USER(HttpStatus.NOT_FOUND, "해당 유저를 찾을 수 없습니다.");
private final HttpStatus status;
private final String error;
}
Java
복사
◦
ErrorResponse Dto
@Getter
@Builder
public class ErrorResponse {
private final String status;
private final String error;
public static ResponseEntity<ErrorResponse> toResponseEntity(CustomException e) {
ErrorCode errorCode = e.getErrorCode();
return ResponseEntity
.status(errorCode.getStatus())
.body(
ErrorResponse.builder()
.status(errorCode.getStatus().name())
.error(errorCode.getError())
.build()
);
}
}
Java
복사
◦
CustomException
@Getter
public class CustomException extends RuntimeException {
private final ErrorCode errorCode;
public CustomException(ErrorCode errorCode) {
super(errorCode.getError());
this.errorCode = errorCode;
}
}
Java
복사
◦
CustomExceptionHandler
@Slf4j
@RestControllerAdvice
public class CustomExceptionHandler {
@ExceptionHandler
protected ResponseEntity<ErrorResponse> handleCustomException(CustomException e) {
return ErrorResponse.toResponseEntity(e);
}
}
Java
복사
•