Contents
see List작성일 2025. 11. 30.
Java 예외 처리 전략
효과적인 예외 처리는 안정적인 애플리케이션의 핵심입니다. 체크 예외와 언체크 예외를 적절히 사용하고, 의미 있는 예외 메시지와 로깅으로 디버깅을 쉽게 만들어야 합니다.
예외 계층 구조
Throwable
├── Error (시스템 오류, 처리 불가)
│ └── OutOfMemoryError, StackOverflowError
└── Exception
├── Checked Exception (컴파일러가 체크)
│ └── IOException, SQLException
└── RuntimeException (Unchecked, 런타임 체크)
└── NullPointerException, IllegalArgumentException체크 vs 언체크 예외 선택 기준
| 체크 예외 | 언체크 예외 |
|---|---|
| 호출자가 복구 가능할 때 | 프로그래밍 오류일 때 |
| 외부 리소스 접근 실패 | 잘못된 인자, null 참조 |
| 반드시 처리해야 할 때 | 개발자 실수 |
커스텀 예외 정의
// 비즈니스 예외 기본 클래스
public class BusinessException extends RuntimeException {
private final ErrorCode errorCode;
public BusinessException(ErrorCode errorCode) {
super(errorCode.getMessage());
this.errorCode = errorCode;
}
public BusinessException(ErrorCode errorCode, Throwable cause) {
super(errorCode.getMessage(), cause);
this.errorCode = errorCode;
}
public ErrorCode getErrorCode() {
return errorCode;
}
}
// 에러 코드 enum
public enum ErrorCode {
USER_NOT_FOUND("U001", "사용자를 찾을 수 없습니다"),
INVALID_PASSWORD("U002", "비밀번호가 일치하지 않습니다"),
DUPLICATE_EMAIL("U003", "이미 등록된 이메일입니다");
private final String code;
private final String message;
// constructor, getters
}
// 구체적인 예외
public class UserNotFoundException extends BusinessException {
public UserNotFoundException() {
super(ErrorCode.USER_NOT_FOUND);
}
}예외 처리 Best Practices
// 1. 구체적인 예외를 먼저 catch
try {
// 작업
} catch (FileNotFoundException e) {
// 파일 없음 처리
} catch (IOException e) {
// 기타 I/O 오류
}
// 2. 예외 체이닝 (원인 보존)
try {
parseData(input);
} catch (ParseException e) {
throw new BusinessException(ErrorCode.PARSE_ERROR, e);
}
// 3. try-with-resources 사용
try (InputStream is = new FileInputStream(file);
BufferedReader reader = new BufferedReader(
new InputStreamReader(is))) {
return reader.readLine();
}
// 4. 불필요한 catch 금지
// BAD
try {
doSomething();
} catch (Exception e) {
throw e; // 의미없는 재던지기
}
// 5. 로깅 후 던지기 (중복 로깅 주의)
try {
process();
} catch (Exception e) {
log.error("처리 실패: {}", e.getMessage());
throw new ProcessException(e);
}Spring 글로벌 예외 처리
@RestControllerAdvice
public class GlobalExceptionHandler {
private static final Logger log =
LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(BusinessException.class)
public ResponseEntity<ErrorResponse> handleBusiness(
BusinessException e) {
log.warn("비즈니스 예외: {}", e.getMessage());
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body(new ErrorResponse(e.getErrorCode()));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleUnexpected(
Exception e) {
log.error("예상치 못한 오류", e);
return ResponseEntity
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(ErrorResponse.of("서버 오류가 발생했습니다"));
}
}
// 에러 응답 DTO
@Getter
public class ErrorResponse {
private String code;
private String message;
private LocalDateTime timestamp;
public ErrorResponse(ErrorCode errorCode) {
this.code = errorCode.getCode();
this.message = errorCode.getMessage();
this.timestamp = LocalDateTime.now();
}
}Optional로 null 예외 방지
// Optional 활용
public User findUser(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException());
}
// null 체크 대신 Optional
Optional.ofNullable(value)
.map(String::trim)
.filter(s -> !s.isEmpty())
.orElse("default");예외 처리 안티패턴
- 빈 catch 블록 (예외 삼키기)
- Exception으로 모든 것 catch
- 예외를 흐름 제어에 사용
- 필요 이상으로 넓은 범위의 try
java
| No | 작성일 | Title |
|---|---|---|
| 3356 | 2026. 08. 14. | Java record와 sealed interface로 안전한 API 응답 모델 만들기 |
| 3324 | 2026. 08. 05. | Java 가상 스레드 실전 적용 가이드: I/O 중심 API의 동시성 구조 바꾸기 |
| 3292 | 2026. 07. 28. | Java 메모리 사용량이 계속 늘어날 때: Heap Dump와 JFR로 누수 원인 찾기 |
| 3261 | 2026. 07. 20. | Java record로 API DTO를 단순하게 만드는 방법: 검증·변환·직렬화 실전 적용 |
| 3235 | 2026. 07. 12. | Java API 동시 호출 폭주 대응: Thread Pool, timeout, 장애 격리로 안정성 올리기 |
| 3178 | 2026. 07. 03. | Java 메모리 누수 진단 가이드: jcmd와 JFR로 원인 좁히기 |
| 3130 | 2026. 06. 25. | Java 가상 스레드 적용 전 점검: 블로킹 I/O와 동시성 제한 운영 가이드 |
| 3074 | 2026. 06. 17. | Java 스레드 작업 취소 설계: interrupt, Future, ExecutorService 종료를 제대로 연결하기 |
| 2985 | 2026. 06. 09. | Java 컨테이너 메모리 운영 가이드: 힙, 직접 메모리, GC 로그를 함께 점검하기 |
| 2928 | 2026. 06. 01. | Java Virtual Threads 운영 전환 가이드: 블로킹 API, 커넥션 풀, 관측 지표 점검법 |