Computer >> 컴퓨터 >  >> 프로그래밍 >> Java

Java 예외 다시 던지기(Rethrow)란? 개념부터 실전 예제까지 총정리

예외 재던지기(Rethrow)란 무엇인가?

Java에서 catch 블록으로 예외를 잡은 후, throw 키워드를 사용해 해당 예외를 다시 던질 수 있습니다. 이를 예외 재던지기(rethrow)라고 하며, 예외를 호출자에게 전달하거나 더 상위 수준의 추상화된 예외로 변환해야 할 때 유용하게 활용됩니다.

재던지기에는 크게 두 가지 방식이 있습니다.

1. 잡은 예외를 그대로 다시 던지기

가장 단순한 방법은 catch 블록에서 잡은 예외 객체를 수정 없이 그대로 throw하는 것입니다.

try {
    int result = (arr[a])/(arr[b]);
    System.out.println("Result of "+arr[a]+"/"+arr[b]+": "+result);
}
catch(ArithmeticException e) {
    throw e;
}

2. 새로운 예외로 감싸서 던지기 (예외 체이닝)

또는 잡은 예외를 새로운 예외 객체로 감싸서(wrap) 던질 수도 있습니다. 이렇게 하면 원래 발생한 저수준 예외를 숨기고 더 높은 수준의 추상화된 예외를 던질 수 있어, 내부 구현 세부사항을 외부에 노출하지 않으면서도 추상화를 유지할 수 있습니다. 이러한 기법을 예외 체이닝(exception chaining) 또는 예외 래핑(exception wrapping)이라고 부릅니다.

try {
    int result = (arr[a])/(arr[b]);
    System.out.println("Result of "+arr[a]+"/"+arr[b]+": "+result);
}
catch(ArrayIndexOutOfBoundsException e) {
    throw new IndexOutOfBoundsException();
}

실전 예제

다음 Java 예제의 demoMethod() 메서드는 ArrayIndexOutOfBoundsException 또는 ArithmeticException이 발생할 수 있는 코드를 포함하고 있습니다. 두 예외는 서로 다른 catch 블록에서 각각 처리되며, 하나는 더 높은 수준의 예외로 감싸서, 다른 하나는 그대로 재던집니다.

import java.util.Arrays;
import java.util.Scanner;
public class RethrowExample {
    public void demoMethod() {
        Scanner sc = new Scanner(System.in);
        int[] arr = {10, 20, 30, 2, 0, 8};
        System.out.println("Array: "+Arrays.toString(arr));
        System.out.println("Choose numerator and denominator(not 0) from this array (enter positions 0 to 5)");
        int a = sc.nextInt();
        int b = sc.nextInt();
        try {
            int result = (arr[a])/(arr[b]);
            System.out.println("Result of "+arr[a]+"/"+arr[b]+": "+result);
        }
        catch(ArrayIndexOutOfBoundsException e) {
            throw new IndexOutOfBoundsException();
        }
        catch(ArithmeticException e) {
            throw e;
        }
    }
    public static void main(String [] args) {
        new RethrowExample().demoMethod();
    }
}

실행 결과 1 — ArithmeticException을 그대로 재던진 경우

분모 위치로 값이 0인 요소(4번 인덱스)를 선택하면 ArithmeticException이 발생하고, catch 블록에서 수정 없이 그대로 다시 던져집니다.

Array: [10, 20, 30, 2, 0, 8]
Choose numerator and denominator(not 0) from this array (enter positions 0 to 5)
0
4
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at myPackage.RethrowExample.demoMethod(RethrowExample.java:16)
    at myPackage.RethrowExample.main(RethrowExample.java:25)

실행 결과 2 — IndexOutOfBoundsException으로 감싸서 던진 경우

배열 범위를 벗어난 위치(124)를 입력하면 ArrayIndexOutOfBoundsException이 발생하지만, catch 블록에서 이를 IndexOutOfBoundsException으로 감싸서 던지므로 스택 트레이스에는 새로운 예외가 출력됩니다.

Array: [10, 20, 30, 2, 0, 8]
Choose numerator and denominator(not 0) from this array (enter positions 0 to 5)
124
5
Exception in thread "main" java.lang.IndexOutOfBoundsException
    at myPackage.RethrowExample.demoMethod(RethrowExample.java:17)
    at myPackage.RethrowExample.main(RethrowExample.java:23)

정리

예외 재던지기는 catch 블록에서 잡은 예외를 그대로 throw하거나, 새로운 예외로 감싸서 던지는 기법입니다. 원본 예외를 그대로 던지면 디버깅 시 원인 파악이 쉬워지고, 반면 예외 체이닝을 활용하면 내부 구현 세부사항을 감추면서 일관성 있고 추상화된 예외 API를 제공할 수 있습니다. 상황에 맞게 두 방식을 적절히 조합하여 사용하는 것이 좋습니다.