공부가 필요했던 예외처리 부분에 대해 정리해보자
예외란?
프로그램 실행 중 발생하는 비정상적인 상황을 의미합니다.
예시로 이해하기
- 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가지
- Checked Exception → 반드시 처리 (컴파일러가 강제)
- Unchecked Exception → 선택적 처리 (개발자 판단)
- 적절한 예외 처리 → 안정적인 프로그램
예외 처리 선택 가이드
예외를 발견했을 때
↓
직접 처리 가능? → YES → try-catch 사용
↓ NO
호출한 곳에서 처리? → YES → throws 사용
↓ NO
비즈니스 규칙 위반? → YES → throw 사용
'-- 오늘 있었던 개발 일기' 카테고리의 다른 글
| solid (0) | 2025.12.07 |
|---|---|
| 오늘의 개발 문제 : context에서 Zustand로 (0) | 2025.12.03 |
| 오늘의 개발 문제 : useState 초기값 설정 (0) | 2025.11.28 |
| 오늘의 개발 문제 : React props 화면에 아무것도 안 보인다... (0) | 2025.11.26 |
| 오늘의 개발 문제 : 실행 환경 보안 정책 (0) | 2025.11.24 |