목적
자바의 예외 처리에 대해 학습하세요.
학습할 것
- 자바에서 예외 처리 방법 (try, catch, throw, throws, finally)
- 자바가 제공하는 예외 계층 구조
- Exception과 Error의 차이는?
- RuntimeException과 RE가 아닌 것의 차이는?
- 커스텀한 예외 만드는 방법
예외란
프로그램 실행 중 발생하는 오류 중, 개발자가 처리해서 프로그램을 계속 진행시킬 수 있는 것을 예외라 한다.
처리하지 않으면 JVM이 프로그램을 종료시킨다.
1. 자바에서 예외 처리 방법 (try, catch, throw, throws, finally)
try-catch
try {
int result = 10 / 0; // 예외 발생 지점
} catch (ArithmeticException e) {
System.out.println("0으로 나눌 수 없습니다: " + e.getMessage());
}
- try 블록에서 예외가 발생하면 그 지점에서 즉시 빠져나와 일치하는 catch 블록으로 이동한다.
- 따라서 예외 발생 이후의 try 블록 코드는 실행되지 않는다.
- catch 블록은 여러 개 둘 수 있고 위에서부터 순서대로 매칭된다.
- 상위 타입인
Exception을 먼저 쓰면 아래쪽은 도달할 수 없어 컴파일 에러가 난다.
finally
try {
// ...
} catch (Exception e) {
// ...
} finally {
// 예외 발생 여부와 관계없이 항상 실행
}
- 예외가 나든 안 나든 반드시 실행된다.
- try나 catch 안에 return이 있어도 실행되기 때문에 자원 반납(close)에 사용한다.
- 자바 7부터는 try-with-resources 가 더 깔끔하다.
try (BufferedReader br = new BufferedReader(new FileReader("a.txt"))) {
return br.readLine();
} // close() 자동 호출
throw 와 throws
// throw : 예외를 직접 발생시킨다
if (age < 0) {
throw new IllegalArgumentException("나이는 음수일 수 없습니다.");
}
// throws : 처리하지 않고 호출한 쪽으로 미룬다
void readFile() throws IOException {
// 여기서 처리 안 함 -> 호출한 쪽이 책임진다
}
이름이 비슷해 헷갈리는데 throw 는 던진다, throws 는 던질 수 있다고 알린다 로 구분하면 된다.
2. 자바가 제공하는 예외 계층 구조
- 모든 예외의 조상은
Throwable이며, 여기서Error와Exception으로 갈린다. - throw 로 던질 수 있는 것은
Throwable을 상속받은 것뿐이다.
3. Exception과 Error의 차이는?
| 구분 | Exception | Error |
|---|---|---|
| 성격 | 프로그램 로직상의 문제 | JVM/시스템 수준의 문제 |
| 복구 가능성 | 가능 | 사실상 불가 |
| 처리 여부 | 개발자가 처리해야 함 | 처리해도 의미 없음 |
| 예 |
IOException, NullPointerException
|
OutOfMemoryError, StackOverflowError
|
핵심은 개발자가 손쓸 수 있느냐다. 메모리가 부족해 OutOfMemoryError 가 났는데 catch 로 잡아봐야 할 수 있는 게 없다.
그래서 Error 는 잡지 않는 것이 정상이다.
4. RuntimeException과 RE가 아닌 것의 차이는?
흔히 Unchecked / Checked 예외로 부른다.
| 구분 | RuntimeException 계열 (Unchecked) | 그 외 (Checked) |
|---|---|---|
| 컴파일러 검사 | 안 함 | 함 (처리 안 하면 컴파일 에러) |
| 처리 의무 | 선택 | 강제 (try-catch 또는 throws) |
| 의미 | 개발자 실수로 발생 | 발생을 예상해야 하는 상황 |
| 예 |
NullPointerException, IndexOutOfBoundsException
|
IOException, SQLException
|
- Checked : 파일이 없을 수도, 네트워크가 끊길 수도 있으니 미리 대비하라는 것
- Unchecked : null 체크를 안 해서 NPE 가 나듯 코드를 잘못 쓴 것
그래서 Unchecked 는 catch 로 막는 게 아니라 코드를 고쳐서 발생하지 않게 하는 것이 맞다.
5. 커스텀한 예외 만드는 방법
기존 예외 클래스를 상속받으면 되고, 어느 쪽을 상속하느냐가 Checked/Unchecked 를 결정한다.
// Unchecked - RuntimeException 상속
public class InsufficientBalanceException extends RuntimeException {
public InsufficientBalanceException(String message) {
super(message);
}
public InsufficientBalanceException(String message, Throwable cause) {
super(message, cause); // 원인 예외를 묶어서 전달
}
}
// Checked - Exception 상속
public class MailSendException extends Exception {
public MailSendException(String message) {
super(message);
}
}
사용할 때는 아래처럼 던진다.
if (balance < amount) {
throw new InsufficientBalanceException(
"잔액 부족: 현재 " + balance + "원, 요청 " + amount + "원");
}
만들 때 주의할 점
- 이름에 상황이 드러나게 짓는다.
MyException보다InsufficientBalanceException - 원인 예외를 버리지 않는다.
super(message, cause)로 넘겨야 스택트레이스가 끊기지 않는다. - 메시지에 판단 근거를 담는다. 위처럼 실제 값을 넣으면 로그만 보고도 원인을 알 수 있다.
- 만들기 전에 표준 예외로 충분한지 본다.
IllegalArgumentException,IllegalStateException으로 되는 경우가 많다.
Reference
남궁성. Java의 정석