예외 재던지기(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를 제공할 수 있습니다. 상황에 맞게 두 방식을 적절히 조합하여 사용하는 것이 좋습니다.