1. 표준 예외
자바 라이브러리는 대부분 API 에서 쓰기에 충분한 수의 예외를 제공하고 있다. 표준 예외를 사용함으로써 내가 작성한 API 가 다른 사람들이 쓰고 익히기에 쉬워질 수 있다. 낯선 예외를 사용하지 않기 때문이다. 그리고, 예외 클래스 수가 적을수록 메모리 사용량도 줄고 클래스를 적재하는 시간도 적게 걸려 표준 예외를 사용하는 것이 좋다.
2. 많이 사용하는 표준 예외
2-1. IllegalArgumentException
가장 많이 사용되는 표준 예외는 IllegalArgumentException 이다. 호출자가 인수로 부적절한 값을 넘길 때 던지는 예외이다. 예를 들어, 반복 횟수를 지정하는 매개변수에 음수를 건넬 때 사용할 수 있다.
public class IllegalArgumentExceptionExample {
// 반복 작업을 수행하는 메서드
public static void repeatTask(int times) {
if (times < 0) {
throw new IllegalArgumentException("반복 횟수는 음수일 수 없습니다: " + times);
}
for (int i = 0; i < times; i++) {
System.out.println("작업을 반복 중: " + (i + 1) + "번째");
}
}
public static void main(String[] args) {
try {
repeatTask(-5); // 부적절한 값 전달
} catch (IllegalArgumentException e) {
System.out.println("예외 발생: " + e.getMessage());
}
}
}
2-2. IllegalStateException
이 예외는 대상 객체의 상태가 호출된 메서들르 수행하기에 적합하지 않을 때 주로 던진다. 예를 들어, 제대로 초기화되지 않은 객체를 사용하려 할 때 던질 수 있다.
public class MyService {
private DatabaseConnection connection; // 초기화되지 않은 객체
// DatabaseConnection 클래스 (간단히 정의)
static class DatabaseConnection {
public void connect() {
System.out.println("데이터베이스에 연결되었습니다.");
}
public void disconnect() {
System.out.println("데이터베이스 연결이 해제되었습니다.");
}
}
// 초기화 메서드
public void initialize() {
connection = new DatabaseConnection(); // 객체 생성 (초기화)
connection.connect(); // 연결 작업 수행
}
// 작업 수행 메서드
public void performTask() {
if (connection == null) { // 초기화 여부 확인
throw new IllegalStateException("DatabaseConnection이 초기화되지 않았습니다. initialize()를 호출하세요.");
}
System.out.println("작업을 수행합니다.");
}
public static void main(String[] args) {
MyService service = new MyService();
try {
service.performTask(); // 초기화되지 않은 상태에서 작업 수행 시도
} catch (IllegalStateException e) {
System.out.println("예외 발생: " + e.getMessage());
}
service.initialize(); // 초기화 수행
service.performTask(); // 정상적으로 작업 수행
}
}
2-3. ConcurrentModificationException
이 예외는 단일 스레드에서 사용하려고 설계한 객체를 여러 스레드가 동시에 수정하려 할 때 던진다. 사실, 동시 수정을 확실히 검출은 못하지만 이 예외는 문제가 생길 가능성을 알려주는 정도의 역할을 하고 있다. 아래 예시와 같이 컬렉션을 반복하면서 동시에 수정하려고 할 때에도 발생할 수 있다.
import java.util.ArrayList;
import java.util.List;
public class ConcurrentModificationExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
try {
// 반복 중 컬렉션을 수정
for (String item : list) {
if ("B".equals(item)) {
list.remove(item); // 반복 중 컬렉션 구조 변경
}
}
} catch (ConcurrentModificationException e) {
System.out.println("예외 발생: " + e);
}
System.out.println("최종 리스트: " + list);
}
}
예외 발생: java.util.ConcurrentModificationException
최종 리스트: [A, C]
2-4. UnsupportedOperationException
이 예외는 클라이언트가 요청한 동작은 대상 객체가 지원하지 않을 때 던진다. 예를 들어, 원소를 넣을 수만 있는 List 구현체에 대고 누군가 remove 메서드를 호출하면 이 예외를 던진다.
import java.util.Arrays;
import java.util.List;
public class UnsupportedOperationExceptionExample {
public static void main(String[] args) {
// 읽기 전용 리스트 생성
List<String> readOnlyList = Arrays.asList("A", "B", "C");
try {
readOnlyList.remove(1); // 읽기 전용 리스트에서 제거 시도
} catch (UnsupportedOperationException e) {
System.out.println("예외 발생: " + e);
}
System.out.println("리스트 내용: " + readOnlyList);
}
}
예외 발생: java.lang.UnsupportedOperationException
리스트 내용: [A, B, C]
Arrays.asList()는 배열을 고정 크기의 리스트로 변환한다. 이 리스트는 요소를 읽을 수는 있지만, 추가나 삭제는 지원하지 않는다. 이 때, 삭제하려고 할 때 UnsupportedOperationException 에러가 발생한다.
3. 정리
Exception, RuntimeException, Throwable, Error 는 직접 재사용하지 말자. 이 예외들은 상위 클래스이므로, 안정적으로 테스트할 수 없다. 아래 널리 재사용되는 예외들을 사용하자.

상황에 부합한다면 항상 표준 예외를 재사용하자. 예외가 던져지는 맥락이 부합해야 한다.
'1️⃣ 백앤드 > 이펙티브 자바' 카테고리의 다른 글
| [아이템74] 메서드가 던지는 모든 예외를 문서화해라 (1) | 2024.12.05 |
|---|---|
| [아이템73] 추상화 수준에 맞는 예외를 던져라 (0) | 2024.12.05 |
| [아이템71] 필요 없는 검사 예외 사용은 피해라 (0) | 2024.12.03 |
| [아이템70] 복구할 수 있는 상황에는 검사 예외를, 프로그래밍 오류에는 런타임 예외를 사용하라 (0) | 2024.12.02 |
| [아이템69] 예외는 진짜 예외 상황에만 사용해라 (0) | 2024.12.02 |