ch9_예외처리

통합 문서입니다.


1. 예외 처리

예외 처리 (Exception Handling)

학습 목표


1. 예외란 무엇인가

예외(Exception)는 프로그램 실행 중 발생하는 비정상 상황을 의미한다.
예외 처리는 문제를 숨기는 기술이 아니라, 문제를 통제 가능한 방식으로 다루는 기술이다.

예:


2. Throwable 계층 구조

큰 구조:

  1. Error: JVM/시스템 수준 심각 문제(보통 애플리케이션 복구 대상 아님)
  2. Exception: 애플리케이션에서 처리 가능한 문제

Exception은 다시:


3. Checked vs Unchecked

3.1 Checked Exception

컴파일러가 처리(또는 위임)를 강제한다.

public String read(Path p) throws IOException { ... }

특징:

3.2 Unchecked Exception

RuntimeException 하위. 컴파일 강제가 없다.

예:

특징:


4. try-catch-finally 기본

try {
    risky();
} catch (SpecificException e) {
    recover();
} finally {
    cleanup();
}

규칙:


5. 예외 전파와 처리 위치

예외는 호출 스택을 따라 위로 전파된다.

예외 전파와 처리 흐름

처리 위치 가이드:

  1. 현재 레이어가 복구 가능하면 여기서 처리
  2. 복구 불가하면 상위로 전달
  3. 경계 레이어(Controller/Batch entry)에서 사용자 친화 메시지/로그 변환

6. throws와 예외 위임

public void importFile(Path path) throws IOException {
    Files.readString(path);
}

throws는 “예외를 무시”가 아니라 “호출자에게 처리 책임 위임”이다.

좋은 위임:

나쁜 위임:


7. try-with-resources (권장)

I/O 자원은 반드시 닫아야 한다.

try (BufferedReader br = Files.newBufferedReader(path)) {
    return br.readLine();
}

장점:


8. 사용자 정의 예외

도메인 규칙 위반을 명확히 표현하기 위해 커스텀 예외를 만든다.

class InsufficientBalanceException extends RuntimeException {
    public InsufficientBalanceException(long balance, long amount) {
        super("balance=" + balance + ", amount=" + amount);
    }
}

장점:


9. 예외 변환(Exception Translation)

하위 기술 예외를 상위 도메인 예외로 감싸 전파하는 패턴.

try {
    repository.save(entity);
} catch (SQLException e) {
    throw new OrderSaveException("주문 저장 실패", e);
}

효과:


10. 예외 처리 모범 사례

  1. 예외를 삼키지 말 것 (catch (Exception e) {} 금지)
  2. 로그는 원인/맥락/입력값을 포함할 것
  3. 정상 흐름 제어를 예외로 대체하지 말 것
  4. 가능한 한 구체 예외를 사용
  5. 메시지는 사용자용/개발자용을 구분

11. 자주 하는 실수

  1. printStackTrace()만 하고 끝냄
  2. 무조건 최상위에서 catch해 원인 맥락 소실
  3. checked 예외를 무의미하게 runtime으로만 래핑
  4. finally에서 또 예외를 내서 원인 예외를 가림
  5. 예외 클래스명이 도메인 의미를 담지 못함

12. 정리


2. 문제

문제

ch9 범위(예외 계층, try-catch, throws, 사용자 정의 예외, 자원 관리) 문제입니다.


A. 기본 예외 처리

  1. 0으로 나누기 예외를 try-catch로 처리하시오.
  2. 배열 인덱스 범위 초과 예외를 재현하고 처리하시오.
  3. NumberFormatException을 처리해 잘못된 입력을 안내하시오.
  4. finally 블록이 항상 실행되는지 확인하시오.

B. checked 예외

  1. 파일 읽기 메소드를 작성하고 IOExceptionthrows로 위임하시오.
  2. 호출부에서 try-catch로 처리하시오.
  3. throws Exception과 구체 예외 선언의 차이를 설명하시오.

C. try-with-resources

  1. 파일을 읽는 코드를 try-finally로 작성하시오.
  2. 같은 코드를 try-with-resources로 리팩터링하시오.
  3. 두 방식의 차이와 장점을 비교하시오.

D. 사용자 정의 예외

  1. InsufficientBalanceException을 작성하시오.
  2. 계좌 출금 로직에서 잔액 부족 시 예외를 발생시키시오.
  3. 상위 레이어에서 예외를 잡아 사용자 메시지로 변환하시오.

E. 예외 변환/전파

  1. Repository에서 발생한 기술 예외를 Service에서 도메인 예외로 변환하시오.
  2. 원인 예외(cause)를 유지한 채 재던지시오.
  3. 최상위 레이어에서 로깅 + 응답 변환을 수행하시오.

F. 챌린지

  1. 회원 가입 유스케이스에서 입력 검증 실패/중복 이메일/DB 실패 예외를 분리 설계하시오.
  2. 배치 처리 중 일부 레코드 실패 시 전체 중단 vs 계속 처리 전략을 구현하시오.
  3. 예외별 에러 코드 체계를 설계하시오.

제출 체크리스트

  1. 예외를 무의미하게 삼키지 않았는가?
  2. 구체 예외를 사용했는가?
  3. 자원 해제가 누락되지 않았는가?
  4. 원인 예외(cause)를 보존했는가?