_

Always be tactful

프로그래밍/배웠어

[Java] '예외 처리' 완전 정복하기

funczun 2025. 1. 7. 01:07
예외 처리

 

 예외 처리란 프로그램 실행 중 발생할 수 있는 오류를 처리하는 기법이다. 즉, 예외가 발생하더라도 프로그램이 갑자기 종료되지 않고, 예외 처리 코드를 통해 문제를 해결할 수 있게 된다. (예외 처리를 하지 않는 경우, 예외가 발생한 지점에서 UncaughtException이 발생하여 프로그램이 비정상적으로 종료된다.)

 

 여기서 예외 발생이라고 함은, 파일을 열고자 하는데 열 파일이 존재하지 않는다거나, 배열의 인덱스를 잘못 참조하는 등 예기치 않은 상황을 말한다. (아래 예시는 배열의 인덱스가 한도를 넘었을 때의 예외다.)

int[] arr = new int[3];
arr[10] = 10; // ArrayIndexOutOfBoundsException 발생

예외 종류

 

 자바에서 예외는 크게 Checked Exception Unchecked Exception으로 나뉜다. Checked Exception은 컴파일 시 반드시 처리해야 하는 예외이며, 예를 들어 입출력 시 발생 가능한 IOException이 있다.

 

 반면, Unchecked Exception은 런타임 시 발생하는 예외이다. 쉽게 말해, RuntimeException을 상속받은 예외들은 컴파일 시 예외 처리가 강제되지는 않는 예외이다. NullPointerException, ArrayIndexOutOfBoundsException 등이 여기에 해당되며, 이러한 예외는 컴파일 에러가 발생하지는 않기 때문에 반드시 처리할 필요는 없다. (그렇다고 해서 처리하지 말라는 것이 아니다. 적절한 오류 메시지 정도는 전달하자.)


사용자 정의 예외

 

 사용자 정의 예외를 통해 직접 예외 클래스를 정의할 수도 있지만, 코드는 언제나 가독성과 유지보수성이 중요하다. 그러니 타 개발자들이 이 예외를 보았을 때에도 어떤 종류의 오류가 발생했는지 쉽게 이해할 수 있도록 자바의 표준 예외를 사용하자.

// 사용자 정의 예외
class MyException extends RuntimeException {
    public MyException(String message) {
        super(message);
    }
}

예외를 던지다

 

 예외를 던진다는 표현은 의도적으로 예외를 발생시켜서 오류 상황을 처리할 수 있도록 시스템에 알리는 것이다. 자바에서 예외를 던지는 구문은 throw다.

if (age < 0) {
    throw new IllegalArgumentException("나이는 음수일 수 없습니다.");
}

 

 예외를 메서드에서 처리하지 않고 호출한 곳으로 넘길 수도 있다. throws를 사용하여 예외를 전파하면 된다.

public class Main {
    public static void main(String[] args) throws IOException {
        FileReader file = new FileReader("file.txt");
        BufferedReader br = new BufferedReader(file);
        System.out.println(br.readLine());
    }
}

예외 처리 방법

 

 자바에서는 try, catch, finally를 사용하여 예외를 처리한다.

  • try: 예외가 발생할 가능성이 있는 코드 (필수)
  • catch: 예외가 발생했을 때, 이를 처리하는 코드 (필수)
  • finally: 예외 발생 여부와 상관없이 항상 실행되는 코드 (선택)
try {
    int result = 10 / 0;  // ArithmeticException 발생
} catch (ArithmeticException e) {
    System.out.println("0으로 나눌 수 없습니다.");
} finally {
    System.out.println("사실 이 블록은 없어도 됩니다.");
}

 

 이외에도 여러 개의 예외를 처리하고자 한다면 아래와 같이 표현할 수 있다.

try {
    String text = null;
    System.out.println(text.length()); // NullPointerException 발생
} catch (NullPointerException e) {
    System.out.println("Null 값을 참조할 수 없습니다.");
} catch (Exception e) {
    System.out.println("기타 예외가 발생하였습니다.");
}

예외 객체 활용

 

 예외 객체는 예외가 발생했을 때 시스템에서 자동으로 생성되어 예외에 대한 정보를 담게 된다. catch에서 이 예외 객체를 사용해 세부 사항을 확인하거나 로그에 기록할 수 있다.

 

 예제 코드에서 쓰인 e는 예외 클래스의 객체를 참조하는 변수로 쓰인 것이며, 이 객체에는 예외와 관련된 여러 정보가 담겨있는 셈이다. (여기서 e는 변수 이름일 뿐이니, 당연히 다른 이름을 써도 된다.)

public class Main {
    public static void main(String[] args) {
        try {
            int result = 10 / 0; // ArithmeticException 발생
        } catch (ArithmeticException e) {
            System.out.println(e.getMessage()); // 예외 메시지 출력
            e.printStackTrace();  // 스택 트레이스 출력
        }
    }
}
728x90