본문 바로가기
Language/Java

[JAVA] 개발자의 숙명, Checked vs Unchecked Exception 깊이 파헤치기

by Papa Martino V 2026. 1. 20.
728x90

Checked vs Unchecked Exception
Checked vs Unchecked Exception

 

 

자바에서 예외(Exception)는 프로그램의 비정상적인 흐름을 제어하기 위한 강력한 메커니즘입니다. 하지만 자바의 예외는 단순히 하나로 분류되는 것이 아니라, 컴파일 시점의 강제성 여부에 따라 Checked Exception(체크 예외)Unchecked Exception(언체크 예외 또는 런타임 예외)으로 나뉩니다. 이 두 가지 예외의 차이를 명확히 이해하는 것은 견고하고 유지보수하기 쉬운 자바 애플리케이션을 개발하는 데 필수적입니다. 오늘은 이 두 가지 예외가 왜 존재하며, 각각 언제 사용해야 하는지, 그리고 실무에서 이들을 어떻게 현명하게 다뤄야 하는지 전문적인 시각으로 분석해 보겠습니다.

1. 예외(Exception)의 두 얼굴: Checked와 Unchecked

자바의 모든 예외는 java.lang.Exception 클래스를 상속받습니다. 이 Exception 클래스에서 RuntimeException을 상속받는 예외들을 Unchecked Exception이라고 부르며, RuntimeException을 상속받지 않는 예외들은 Checked Exception입니다.

2. Checked Exception: 컴파일러의 강제성

Checked Exception은 이름 그대로 컴파일러가 반드시 예외 처리 여부를 체크하는 예외입니다. 개발자는 이러한 예외가 발생할 가능성이 있는 코드에 대해 try-catch 블록으로 직접 처리하거나, 해당 예외를 호출자에게 throws 키워드를 사용하여 전파해야 합니다. 이를 강제하지 않으면 컴파일 오류가 발생합니다.

2.1. Checked Exception의 특징

  • 강제성: 컴파일 시점에 예외 처리 코드를 강제합니다.
  • 복구 가능성: 주로 외부 요인(파일 입출력, 네트워크 통신, 데이터베이스 접근)으로 인해 발생하며, 애플리케이션 로직에서 복구 가능한 상황을 나타냅니다. (예: 파일을 찾을 수 없을 때, 네트워크 연결이 끊겼을 때)
  • 예시: IOException, SQLException, ClassNotFoundException

2.2. 언제 Checked Exception을 사용해야 하는가?

메서드를 호출하는 쪽에서 해당 예외를 인지하고 복구 로직을 작성할 수 있거나, 적어도 예외 발생 사실을 알고 다음 단계를 결정해야 할 때 사용합니다. 즉, 호출자가 문제를 해결할 책임이 있는 경우에 적합합니다.

import java.io.FileReader;
import java.io.IOException;

public class CheckedExceptionExample {
    public static void readFile(String filePath) throws IOException { // throws로 예외 전파
        FileReader reader = new FileReader(filePath);
        // 파일 읽기 로직...
        reader.close();
    }

    public static void main(String[] args) {
        try {
            readFile("nonexistent.txt");
        } catch (IOException e) { // try-catch로 예외 처리 강제
            System.err.println("파일 읽기 오류: " + e.getMessage());
            // 복구 로직 또는 대체 동작 수행
        }
    }
}

3. Unchecked Exception (RuntimeException): 개발자의 실수

Unchecked Exception은 컴파일러가 예외 처리 여부를 강제하지 않는 예외입니다. RuntimeException을 상속하는 모든 예외가 여기에 해당합니다. 주로 개발자의 부주의나 로직상의 오류(버그)로 인해 발생하며, 이러한 예외는 사실상 복구하기 어렵고 프로그램의 정상적인 동작을 방해하는 경우가 많습니다.

3.1. Unchecked Exception의 특징

  • 자율성: 컴파일 시점에 예외 처리 코드를 강제하지 않습니다. 개발자가 명시적으로 처리하지 않아도 컴파일은 됩니다.
  • 개발자 실수: 주로 프로그래밍 오류(NullPointerException, IndexOutOfBoundsException), 잘못된 인자 값 전달(IllegalArgumentException) 등으로 발생합니다.
  • 예시: NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException

3.2. 언제 Unchecked Exception을 사용해야 하는가?

대부분의 Unchecked Exception은 개발자가 코드를 더 주의 깊게 작성하여 발생 자체를 막아야 하는 경우입니다. 예를 들어, 메서드의 인자로 null이 넘어올 가능성이 있다면 NullPointerException 대신 사전에 null 체크를 하여 방지해야 합니다.

public class UncheckedExceptionExample {
    public static void accessArray(int[] arr, int index) {
        // 배열 인덱스 유효성 검사로 예외 방지
        if (arr == null || index < 0 || index >= arr.length) {
            throw new IllegalArgumentException("Invalid array or index provided.");
        }
        System.out.println(arr[index]);
    }

    public static void main(String[] args) {
        int[] numbers = {1, 2, 3};
        // Unchecked Exception은 try-catch가 필수는 아님 (하지만 필요에 따라 할 수는 있음)
        accessArray(numbers, 5); // ArrayIndexOutOfBoundsException 발생 가능
        // accessArray(null, 1); // NullPointerException 발생 가능
    }
}

4. Checked vs Unchecked Exception 비교 요약

두 예외 유형의 핵심적인 차이를 한눈에 비교해 보세요.

구분 Checked Exception Unchecked Exception (RuntimeException)
상속 관계 Exception 상속 (RuntimeException 제외) RuntimeException 상속
컴파일 강제 예 (try-catch 또는 throws 필수) 아니오 (자율)
복구 가능성 복구 가능성 높음 (외부 환경 문제) 복구 불가능성 높음 (개발자 로직 오류)
예시 IOException, SQLException, InterruptedException NullPointerException, IllegalArgumentException, ArithmeticException
주요 목적 API 사용자에게 예외 처리 강제 및 안정성 보장 개발자에게 프로그래밍 오류 발생 알림

5. 실무에서의 현명한 예외 처리 전략

  1. Checked Exception은 꼭 필요한 곳에만: 너무 많은 Checked Exception은 코드 복잡도를 높이고, 개발자에게 불필요한 예외 전파를 강제하여 오히려 생산성을 저해할 수 있습니다. 정말로 복구가 필요한 외부 연동 구간에 집중해서 사용합니다.
  2. Unchecked Exception은 방지 우선: Unchecked Exception은 버그의 신호입니다. try-catch로 잡기보다, 예외가 발생하지 않도록 사전 유효성 검사, 방어적 코드 작성 등을 통해 근본적으로 방지하는 것이 중요합니다.
  3. 비즈니스 예외는 Custom Unchecked Exception으로: 도메인 특유의 비즈니스 규칙 위반 상황(예: "재고 부족", "사용자 권한 없음")은 RuntimeException을 상속하는 Custom Unchecked Exception으로 정의하여, 서비스 계층에서 일관된 방식으로 처리하고 프레젠테이션 계층으로 전달하는 것이 효율적입니다.
  4. 로깅은 필수: 어떤 종류의 예외든 발생 시에는 반드시 적절한 레벨로 로깅하여 문제 발생의 흔적을 남겨야 합니다.

6. 결론: 목적에 맞는 예외 선택과 처리

Checked Exception과 Unchecked Exception은 각각 다른 목적을 가지고 있습니다. Checked Exception은 API 사용자의 책임과 복구 가능성을 강조하며 시스템의 견고함을 높이고, Unchecked Exception은 개발자의 실수를 빠르게 인지하고 수정하도록 돕습니다.

이 둘의 차이를 명확히 이해하고, 여러분의 애플리케이션의 특성과 비즈니스 로직에 맞춰 최적의 예외 처리 전략을 수립하는 것이 자바 개발자의 중요한 역량입니다.


참고 문헌 및 출처

  • Oracle Java Documentation: The Java™ Tutorials - Exceptions
  • Joshua Bloch, "Effective Java 3rd Edition", Addison-Wesley Professional.
  • Martin Fowler, "Refactoring: Improving the Design of Existing Code", Addison-Wesley. (특히 Assertion과 Exception 관련 내용)
728x90