본문 바로가기
-- 오늘 있었던 개발 일기

자바의 예외 처리(Exception) 구조

by code study 2025. 11. 30.

공부가 필요했던 예외처리 부분에 대해 정리해보자

 

예외란?

프로그램 실행 중 발생하는 비정상적인 상황을 의미합니다.

예시로 이해하기

  • 0으로 나누기 시도
  • 존재하지 않는 파일 열기
  • 배열의 범위를 벗어난 접근

예외 처리는 이런 오류 상황을 프로그램이 적절히 다루어 갑자기 꺼지지 않도록 하는 메커니즘입니다.


예외 클래스 계층 구조

Object
  └─ Throwable
       ├─ Error (시스템 오류 - 처리 불가)
       │    ├─ OutOfMemoryError (메모리 부족)
       │    └─ StackOverflowError (스택 오버플로우)
       │
       └─ Exception (프로그램 오류 - 처리 가능)
            ├─ IOException (파일 입출력 오류)
            ├─ SQLException (데이터베이스 오류)
            └─ RuntimeException
                 ├─ NullPointerException (null 참조)
                 ├─ ArrayIndexOutOfBoundsException (배열 범위 초과)
                 └─ ArithmeticException (산술 오류)

 

핵심 포인트

  • Error: 프로그램에서 처리할 수 없는 심각한 오류
  • Exception: 프로그램에서 처리 가능한 오류

Checked vs Unchecked Exception

간단 비교표

구분 Checked Unchecked
처리 강제 필수 (컴파일러가 체크) 선택 (개발자 판단)
발생 시점 컴파일 시 실행 시
주요 원인 외부 요인 (파일, 네트워크) 프로그래밍 실수
대표 예제 IOException, SQLException NullPointerException

 


실제 예시

Checked Exception - 반드시 처리해야 함

// 컴파일 오류 발생! (처리 안 하면 실행 자체가 안 됨)
FileReader file = new FileReader("data.txt");

// 올바른 처리
try {
    FileReader file = new FileReader("data.txt");
} catch (IOException e) {
    System.out.println("파일을 찾을 수 없습니다!");
}

 

Unchecked Exception - 처리 선택

// 컴파일은 되지만 실행 시 오류 발생
String str = null;
str.length(); // NullPointerException!

// 처리는 선택사항
if (str != null) {
    str.length();
}

예외 처리 3가지 방법

1️⃣ try-catch (직접 처리)

try 블록에 위험한 코드, catch 블록에 처리 코드를 넣습니다.

try {
    int result = 10 / 0; // 오류 발생!
} catch (ArithmeticException e) {
    System.out.println("0으로 나눌 수 없습니다");
}

 

여러 개 처리하기

여러 개의 catch를 붙여서 각각 다르게 처리할 수도 있습니다.

try {
    String data = "abc";
    int value = Integer.parseInt(data); // 숫자 변환 실패

} catch (NumberFormatException e) {
    System.out.println("숫자가 아닙니다!");
} catch (Exception e) {
    System.out.println("기타 오류 발생");
}

2️⃣ throws (나중에 처리)

메서드에 throws를 붙이면 호출한 쪽에서 처리하게 됩니다.

// 메서드를 호출한 쪽에서 처리하도록 넘김
public void readFile() throws IOException {
    FileReader file = new FileReader("data.txt");
}

// 호출하는 쪽에서 처리
public void process() {
    try {
        readFile();
    } catch (IOException e) {
        System.out.println("파일 읽기 실패");
    }
}

3️⃣ throw (의도적으로 발생)

조건에 맞지 않으면 직접 예외를 발생시킵니다.

public void setAge(int age) {
    if (age < 0) {
        throw new IllegalArgumentException("나이는 음수일 수 없습니다");
    }
    this.age = age;
}

실전 예제 - 은행 계좌

public class BankAccount {
    private int balance = 10000; // 잔액 1만원

    public void withdraw(int amount) {
        try {
            // 1. 출금액 검사
            if (amount <= 0) {
                throw new Exception("출금액은 0보다 커야 합니다");
            }

            // 2. 잔액 검사
            if (balance < amount) {
                throw new Exception("잔액이 부족합니다");
            }

            // 3. 출금 처리
            balance -= amount;
            System.out.println("출금 완료! 잔액: " + balance + "원");

        } catch (Exception e) {
            System.out.println("출금 실패: " + e.getMessage());
        }
    }
}

 

사용 예시

BankAccount account = new BankAccount();
account.withdraw(5000);   // 출금 완료! 잔액: 5000원
account.withdraw(-1000);  // 출금 실패: 출금액은 0보다 커야 합니다
account.withdraw(10000);  // 출금 실패: 잔액이 부족합니다

 예외 처리를 사용하는 이유

이유 설명
🛡️ 프로그램 보호 오류가 나도 프로그램이 꺼지지 않음
📋 명확한 오류 메시지 무엇이 잘못되었는지 알 수 있음
📖 코드 정리 정상 코드와 오류 처리를 분리
🔧 유지보수 편리 오류 상황을 체계적으로 관리

✅ 올바른 예외 처리 vs ❌ 잘못된 예외 처리

❌ 잘못된 예외 처리

// 1. 빈 catch 블록 (오류를 숨김)
try {
    // 코드
} catch (Exception e) {
    // 아무것도 안 함 - 최악!
}

// 2. 모든 것을 Exception으로 처리
try {
    // 코드
} catch (Exception e) {
    // 너무 광범위
}

✅ 올바른 방법

// 구체적인 예외를 명확하게 처리
try {
    processFile();
} catch (FileNotFoundException e) {
    System.out.println("파일이 없습니다: " + e.getMessage());
} catch (IOException e) {
    System.out.println("파일 읽기 오류: " + e.getMessage());
}

핵심 정리

꼭 기억해야 할 3가지

  1. Checked Exception → 반드시 처리 (컴파일러가 강제)
  2. Unchecked Exception → 선택적 처리 (개발자 판단)
  3. 적절한 예외 처리 → 안정적인 프로그램

예외 처리 선택 가이드

예외를 발견했을 때
    ↓
직접 처리 가능? → YES → try-catch 사용
    ↓ NO
호출한 곳에서 처리? → YES → throws 사용
    ↓ NO
비즈니스 규칙 위반? → YES → throw 사용