문제 상황
수행하려는 일과 관련 없는 예외가 튀어나오면 당황스럽다.
고수준 메소드가 저수준의 예외 처리하지 않고 바깥으로 전파해버릴 때 발생하는 문제다.
해결 방법
상위 계층 저수준 예외를 잡아 자신의 추상화 수준에 맞는 예외로 바꿔야한다.
try {
// 저수준 예외 발생
} catch (LowerLevelException e) {
// 추상화 수준에 맞게 번역
throw new HigherLevelException(...)
}
왜, 언제 사용하는가?
저 수준의 예외가 디버깅에 도움이 될 때다.
예외 번역 (Exception Translation)
class AbstractSquentialList {
/*
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
try {
return listIterator(index).next();
} catch (NoSuchElementException exc) {
// 저수준의 NoSuchElement 상황을
// 고수준 Exception 으로 '어느 index' 에서 에러가 났는지 감싼다.
throw new IndexOutOfBoundsException("Index: "+index);
}
}
}
하위레벨 NoSuchElementException 의 Cause 를 숨기고
고수준의 Exception 정보만 노출시킨다.
"필요한 고수준 정보만 유저에게 노출한다" 가 핵심이다.
예외 연쇄 (Exception Chaining)
저수준의 근본 원인(Cause)를 고수준 예외에 실어 보내는 기법.,
try {
// 저수준 추상화
} catch (LowerLevelException cause) {
// 저수준 예외를 고수준에 실어 보냄
throw new HigherLevelException(cause);
}
디버깅 해상도를 높이기 위해 고수준 Exception 에서 저수준 Exception Cause 를 실어 노출시킨다.
예외 연쇄는 "깊은 디버깅을 위해 저수준 에러 로그를 노출한다" 가 핵심이다.
HigherLevelException 에 메시지만 더하는 예외 번역 기법에서는 하위레벨 로그가 노출되지 않아 디버깅이 어려울 때가 있다.
이럴 때 예외 연쇄를 적용할 수 있다.
예외 번역 + 연쇄 조합 사용
둘의 장점을 조합한 기법이다.
대부분의 Java Exception 은 고수준에서 번역된 예외 메시지를 작성하고, 저수준 예외도 같이 실어 보낼 수 있다.
public class IllegalArgumentException extends RuntimeException {
// ..
public IllegalArgumentException(String message, Throwable cause) {
super(message, cause);
}
}
try {
// 저수준 추상화
} catch (LowerLevelException cause) {
// 에러 메시지를 번역하고 + 저수준 예외를 고수준에 실어 보냄
throw new HigherLevelException("Higher level exception", cause);
}
요약
구분 | Exception Translation | Exception Chaining |
저수준 Cause 유지 여부 | X | O |
Debugging 상세 수준 | 고수준 | 저수준 |
사용 목적 | 필요한 정보만 고수준의 예외로 노출 저수준 Exception 을 은닉 |
상세한 디버깅을 위한 원본 Cause 노출 |
'JVM > Java' 카테고리의 다른 글
[Java] Thread 상속 대신 Runnable 을 사용하라. (0) | 2024.07.21 |
---|---|
[Java] Guava - MultiMap , BiMap (0) | 2024.07.14 |
[Java] Generic vs WildCard (2) | 2024.01.07 |
[객체지향] 잘못된 DRY 원칙 적용 (0) | 2023.12.16 |
[Java] Enum 에는 equals 대신 == 을 써라 (0) | 2023.11.22 |