CodeGym /행동 /JAVA 25 SELF /Java의 예외 계층 구조

Java의 예외 계층 구조

JAVA 25 SELF
레벨 24, 레슨 0
사용 가능

1. 클래스 Throwable: 모든 예외의 루트

지금부터 Java의 예외 시스템이 어떻게 구성되어 있는지 자세히 살펴보겠습니다. Throwable이 무엇인지, Exception과 Error는 어떻게 다른지, 그리고 “체크 예외”와 “언체크 예외”는 무엇을 의미하는지 알아봅니다. 이는 프로그램에서 올바르게 오류를 처리하기 위한 기초입니다.

Java에서 모든 예외와 오류는 java.lang.Throwable 클래스를 상속하는 객체입니다.
Throwable은 Java에서 문제를 처리하는 전체 계층의 “조상”입니다.

개략적으로:

Throwable
├── Exception
└── Error

Throwable은 Java에서 “던질” 수 있고(throw) “잡을” 수 있는(catch) 모든 것의 기본 클래스입니다. 직접 사용하는 클래스가 아니며, 보다 구체적인 오류 타입을 위한 기반으로 쓰입니다.

Exception — 일상적인(업무) 오류용

Exception은 프로그램에서 발생할 수 있고 처리해야 하는 모든 예외의 기본 클래스입니다. 이는 파일, 네트워크, 입출력, 사용자 입력 등과 관련된 “업무” 오류입니다. 여러분의 대부분의 try-catch는 Exception의 하위 클래스와 함께 동작합니다.

예시:

  • IOException — 파일 또는 네트워크 작업 중 오류.
  • SQLException — 데이터베이스 작업 중 오류.
  • FileNotFoundException — 파일을 찾을 수 없음.

Error — JVM의 치명적 오류용

Error는 Java 가상 머신(JVM) 수준에서 발생하는 오류의 기본 클래스입니다. 보통 프로그램이 처리할 수 없고 처리해서도 안 되는 치명적 장애입니다. Error가 발생하면 애플리케이션은 대개 작업을 계속할 수 없습니다.

예시:

  • OutOfMemoryError — 메모리가 고갈됨.
  • StackOverflowError — 스택 오버플로(예: 무한 재귀로 인해).
  • NoClassDefFoundError — 필요한 클래스를 찾을 수 없음.

중요:
Error를 잡아 처리하는 것은 거의 항상 좋지 않은 선택입니다. 이는 여러분의 코드 문제가 아니라 실행 환경의 문제입니다.

2. Checked vs Unchecked exceptions: 무슨 뜻인가요?

Java의 모든 예외는 두 가지 큰 그룹으로 나뉩니다:

체크 예외(Checked)

무엇인가? 컴파일러가 반드시 처리하거나 명시적으로 더 위로 전파하도록 강제하는 예외입니다.

언제 발생하나? 보통 외부 리소스와 관련됩니다: 파일, 네트워크, 데이터베이스, 사용자 입력 등.

어떻게 처리하나? 코드를 try-catch로 감싸거나, 메서드 시그니처에 throws를 추가해야 합니다.

예시: IOException, SQLException, FileNotFoundException

예제:

public void readFile(String path) throws IOException {
    FileReader reader = new FileReader(path); // IOException을 던질 수 있음
    // ...
}

처리하거나 전파하지 않으면 — 프로그램은 컴파일되지 않습니다!

언체크 예외(Unchecked)

무엇인가? 컴파일러가 강제하지 않는 예외입니다.

언제 발생하나? 보통 프로그램 로직의 오류입니다: 0으로 나누기, 배열 범위 초과, null 참조 접근 등.

어떻게 처리하나? 잡을 수는 있지만 필수는 아닙니다. 이런 오류는 사전 검증으로 예방하는 것이 좋습니다.

계층에서의 위치? 모두 RuntimeException을 상속합니다.

예시: NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException, ArithmeticException

예제:

int[] arr = {1, 2, 3};
System.out.println(arr[10]); // ArrayIndexOutOfBoundsException

컴파일러는 이 예외를 잡도록 강제하지 않습니다 — 그러나 오류가 발생하면 프로그램은 “크래시”됩니다.

3. 전체 계층을 한 그림으로

graph TD
    Throwable --> Error
    Throwable --> Exception
    
    Exception --> RuntimeException
    Exception --> CheckedExceptions["(기타 체크 예외)"]
    
    Error --> OutOfMemoryError
    Error --> StackOverflowError
    
    RuntimeException --> NullPointerException
    RuntimeException --> IndexOutOfBoundsException
    RuntimeException --> IllegalArgumentException

    %% 스타일
    style Throwable fill:#ffa64d,color:#000
    style Exception fill:#ffa64d,color:#000
    style CheckedExceptions fill:#ffa64d,color:#000
    
    style Error fill:#ff4d4d,color:#fff
    style OutOfMemoryError fill:#ff4d4d,color:#fff
    style StackOverflowError fill:#ff4d4d,color:#fff
    
    style RuntimeException fill:#4dff88,color:#000
    style NullPointerException fill:#4dff88,color:#000
    style IndexOutOfBoundsException fill:#4dff88,color:#000
    style IllegalArgumentException fill:#4dff88,color:#000

표: 주요 차이점

그룹 부모 클래스 처리가 필요한가? 예시
체크 예외
Exception
예
IOException, SQLException
언체크
RuntimeException
아니오
NullPointerException, IndexOutOfBoundsException
Error
Error
아니오
OutOfMemoryError, StackOverflowError

4. 코드에서는 어떻게 보이나요?

Checked Exception: 파일 예시

import java.io.*;

public class FileDemo {
    public static void main(String[] args) {
        try {
            FileReader reader = new FileReader("nofile.txt"); // FileNotFoundException (checked)
            int data = reader.read();
            System.out.println(data);
            reader.close();
        } catch (IOException e) {
            System.out.println("파일 작업 중 오류: " + e.getMessage());
        }
    }
}

컴파일러는 IOException 처리를 요구합니다!

Unchecked Exception: 0으로 나누기 예시

public class ExceptionDemo {
    public static void main(String[] args) {
        int a = 10;
        int b = 0;
        int c = a / b; // ArithmeticException (unchecked)
        System.out.println("결과: " + c);
    }
}

컴파일러는 처리를 요구하지 않지만, 프로그램은 “크래시”됩니다.

5. 왜 예외 계층이 필요한가?

  • 처리의 유연성: 특정 오류(FileNotFoundException)부터 전체 그룹(IOException 또는 Exception)까지 선택적으로 잡을 수 있습니다.
  • 코드 재사용: 동일한 유형의 오류를 중앙집중식으로 처리할 수 있습니다.
  • 코드의 간결함: 사소한 검사로 본래의 비즈니스 로직이 어수선해지지 않습니다.

예제:

try {
    // 위험한 코드
} catch (FileNotFoundException e) {
    System.out.println("파일을 찾을 수 없습니다!");
} catch (IOException e) {
    System.out.println("입출력 오류!");
} catch (Exception e) {
    System.out.println("문제가 발생했습니다: " + e.getMessage());
}

6. 예외 처리 시 자주 하는 실수

오류 № 1: 예외를 무시함. catch (Exception e) {}처럼 비워 두는 것은 좋지 않습니다! 오류 원인에 대한 정보를 잃습니다.

오류 № 2: 너무 많이 잡음. catch (Exception e)는 예상하지 못한 것까지 모조리 잡습니다. 처리할 수 있는 예외만 잡는 것이 좋습니다.

오류 № 3: Error를 잡음. 저수준 코드를 작성하는 것이 아니라면 Error를 잡지 마세요. 이는 JVM의 문제이지 여러분 프로그램의 문제가 아닙니다.

오류 № 4: checked와 unchecked를 구분하지 않음. 모든 예외가 같은 것은 아닙니다! checked는 처리해야 하고(Exception), unchecked는 필수가 아닙니다(RuntimeException 및 그 하위 클래스).

오류 № 5: 예외에 정보를 추가하지 않음. 사용자 정의 예외를 만들 때는 항상 정보가 담긴 메시지를 추가하세요.

1
과제
JAVA 25 SELF, 레벨 24, 레슨 0
잠금
예외의 미스터리: 부모 계층
예외의 미스터리: 부모 계층
1
과제
JAVA 25 SELF, 레벨 24, 레슨 0
잠금
누가 주인인가? 예외와 오류의 차이
누가 주인인가? 예외와 오류의 차이
1
과제
JAVA 25 SELF, 레벨 24, 레슨 0
잠금
알림 시스템: 검사 예외와 비검사 예외
알림 시스템: 검사 예외와 비검사 예외
1
과제
JAVA 25 SELF, 레벨 24, 레슨 0
잠금
사서 로봇과 그의 "구조 계획"
사서 로봇과 그의 "구조 계획"
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION