8.3 사용자 정의 예외 (Custom Exceptions)
자바가 기본적으로 제공하는 수많은 예외 클래스(NullPointerException, FileNotFoundException 등)만으로도 대부분의 오류 상황을 처리할 수 있습니다.
하지만, 실제 실무 웹 서비스나 앱을 개발하다 보면 "잔고 부족 예외", "입력값이 금지어임 예외", "회원 등급 미달 예외" 등 우리 비즈니스 로직에만 존재하는 특수한 에러 상황 을 표현해야 할 때가 생깁니다. 이때 개발자가 직접 클래스를 만들어 사용하는 것을 사용자 정의 예외(Custom Exception) 라고 합니다.
1. 사용자 정의 예외 만들기
사용자 정의 예외를 만드는 방법은 아주 간단합니다. 자바가 제공하는 Exception 클래스나 RuntimeException 클래스를 상속(extends) 받기만 하면 됩니다.
Exception상속: 반드시try-catch로 예외 처리를 해주어야 하는 엄격한 에러(Checked Exception)를 만들 때RuntimeException상속:(최근 실무 권장) 필요할 때만 처리하고 컴파일러가 강제하지 않는 유연한 에러(Unchecked Exception)를 만들 때
예제: 잔고 부족 예외 클래스 작성
은행 계좌 출금 시스템을 만든다고 가정해 봅시다. 출금하려는 금액이 현재 잔고보다 크면 에러를 내야 합니다.
// RuntimeException을 상속받아 사용자 정의 예외 클래스를 생성
public class BalanceInsufficientException extends RuntimeException {
// 1. 기본 생성자
public BalanceInsufficientException() {
super("잔고가 부족합니다."); // 기본 에러 메시지 세팅
}
// 2. 에러 메시지를 직접 입력받을 수 있는 생성자
public BalanceInsufficientException(String message) {
super(message); // 부모 클래스의 생성자를 호출하여 메세지 전달
}
}
2. 예외 일부러 발생시키기: throw 키워드
우리가 만든 예외를 써먹으려면, 에러 조건이 발생했을 때 자바에게 "방금 내가 만든 에러가 터졌어!" 라고 알려주어야 합니다. 이때 사용하는 키워드가 throw(던지다) 입니다.
주의: 예외를 처리하는 구문은
try-catch이고, 예외를 능동적으로 발생시키는 키워드는throw입니다.
public class Account {
private long balance; // 통장 잔고
public Account(long balance) {
this.balance = balance;
}
public void withdraw(int money) {
// 출금 금액이 잔고보다 크면 에러를 만들어 던집니다!
if (this.balance < money) {
// throw 키워드를 사용해 방금 만든 예외 객체를 던집니다.
throw new BalanceInsufficientException("잔고 부족: " + (money - this.balance) + "원이 더 필요합니다.");
}
this.balance -= money;
System.out.println(money + "원 출금 완료. 남은 잔고: " + this.balance);
}
}
3. 메인 프로그램에서 적용하기
이제 위에서 만든 계좌 모델과 사용자 정의 예외를 가져다 써보겠습니다.
public class CustomExceptionTest {
public static void main(String[] args) {
// 10,000원이 들어있는 통장 개설
Account myAccount = new Account(10000);
try {
// 3,000원 출금 시도 (정상)
myAccount.withdraw(3000);
// 20,000원 출금 시도 (에러 발생 예정!)
myAccount.withdraw(20000);
} catch (BalanceInsufficientException e) {
// 우리가 만든 예외 클래스로 catch 가능!
System.out.println("출금에 실패했습니다.");
// 에러 메시지는 '잔고 부족: 13000원이 더 필요합니다.' 가 들어있게 됩니다.
System.out.println("사유: " + e.getMessage());
} catch (Exception e) {
System.out.println("알 수 없는 에러가 발생했습니다.");
}
}
}
[실행 결과]
3000원 출금 완료. 남은 잔고: 7000
출금에 실패했습니다.
사유: 잔고 부족: 13000원이 더 필요합니다.
왜 사용자 정의 예외를 쓸까요?
- 코드의 가독성:
if (balance < money)일 때 에러 코드로-1을 반환하는 것보다,throw new BalanceInsufficientException()을 던지는 것이 누가 봐도 잔고 부족 에러임을 명확히 알 수 있습니다. - 세밀한 제어: 에러 클래스 이름 자체로 에러의 종류를 구분하므로, 서로 다른 에러를 담당하는
catch블록을 여러 개 만들어 정교하고 섬세한 비즈니스 처리가 가능해집니다.
지금까지 프로그램의 붕괴를 막고 우아하게 복구하는 자바 예외 처리 의 기초부터 사용자 정의 예외까지 마스터하셨습니다! 다음 챕터부터는 자바 언어의 핵심 코어 패키지인 java.lang 패키지에 대해 다뤄보겠습니다.