[아이템72] 표준 예외를 사용하라

2024. 12. 3. 20:00·1️⃣ 백앤드/이펙티브 자바

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
'1️⃣ 백앤드/이펙티브 자바' 카테고리의 다른 글
  • [아이템74] 메서드가 던지는 모든 예외를 문서화해라
  • [아이템73] 추상화 수준에 맞는 예외를 던져라
  • [아이템71] 필요 없는 검사 예외 사용은 피해라
  • [아이템70] 복구할 수 있는 상황에는 검사 예외를, 프로그래밍 오류에는 런타임 예외를 사용하라
HOZINU
HOZINU
주니어 백앤드 개발자의 세상만사 이모저모. 주로 개발 이야기를 다룸.
  • HOZINU
    백엔드 탐험 일지
    HOZINU
  • 전체
    오늘
    어제
  • 블로그 메뉴

    • ⛪ HOME
    • 🌍 GITHUB
    • 카테고리 (73)
      • 1️⃣ 백앤드 (72)
        • 이펙티브 자바 (72)
      • 2️⃣ CS (0)
        • 운영체제 (0)
        • 네트워크 기초 (0)
        • 네트워크 응용 (0)
        • SSL & PKI (0)
        • 기타 (0)
      • 3️⃣ 코딩테스트 (0)
      • 4️⃣ 개인공부 (0)
        • MSA (0)
        • REDIS (0)
      • 5️⃣ 일상이야기 (1)
  • 인기 글

  • 태그

    정적 팩터리 메서드
    Comparable
    try-with-resources
    Cleaner
    hashcode
    equals
    로타입
    정보은닉
    표준예외
    CLONE
    finalizer
    캡슐화
    optional
    싱글턴
    컴포지션
    빌더
    멤버클래스
    맥북
    의존객체
    계층구조
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
HOZINU
[아이템72] 표준 예외를 사용하라
상단으로

티스토리툴바