이번에는 UncaughtExceptionHandler 에 대해 알아보겠다.
사실 내가 보는 책이나 강의들에서는 잠깐 언급하고 지나갔지만, 내가 보기에는 꽤 중요한 부분이라고 생각되어서 따로 공부해서 적었다.
Thread에 대한 JAVA api 를 확인하면 내부에 이러한 인터페이스가 있는 것을 발견할 수 있다.
//Thread 내부
@FunctionalInterface
public interface UncaughtExceptionHandler {
void uncaughtException(Thread t, Throwable e);
}
// null unless explicitly set
private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
쓰레드에서 uncaughtException(처리되지 않은 예외)로 인해 쓰레드가 종료되려고 할 때,
JVM은 쓰레드에게 Thread.getUncaughtExceptionHandler()
을 통해 uncaughtExceptionHandler를 얻어냅니다.
그리고 인수로 Thread와 Throwable을 넣어서 uncaughtException 메서드를 실행합니다.
이때 만약 명시적으로 UncaughtExceptionHandler가 설정되지 않았다면,
ThreadGroup 오브젝트가 UncaughtExceptionHandler처럼 동작합니다.
만약 ThreadGroup 에 처리를 위한 특별한 요구사항이 없는 경우 Thread.getDefaultUncaughtExceptionHandler
를 통해 얻어낸 defaultUncaughtExceptionHandler 를 통해 처리하려고 한다.
만약 이 마저도 없다면 아래와 같이 처리한다.
Thread.uncaughtExceptionHandler
ThreadGroup.uncaughtException()
Thread.defaultUncaughtExceptionHandler
public class ThreadGroup implements Thread.UncaughtExceptionHandler {
//...
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
} else {
Thread.UncaughtExceptionHandler ueh =
Thread.getDefaultUncaughtExceptionHandler();
if (ueh != null) {
ueh.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
System.err.print("Exception in thread \""
+ t.getName() + "\" ");
e.printStackTrace(System.err);
}
}
}
//...
}
즉 우리는 UncaughtExceptionHandle 을 하기 위해 아래와 같은 선택지가 있다.
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh)
ThreadGroup.uncaughtException()
를 자손클래스에서 오버라이드public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh)
을 통해 바꿀 수 있다.이 모든 단계는 앞의 단계가 null 일때 다음 단계를 검토한다.
즉 이 처리를 잘 적용하면 기본적인 에러를 쭉 print 하는 것이 아닌, 로그를 남긴다던가, 기록을 한다던가 하는 모든 처리가 가능하다.
그리고 마지막으로 api에는 이러한 줄이 적혀있다.
uncaughtException
Any exception thrown by this method will be ignored by the Java Virtual Machine.
이 메서드에서 던져지는 어떠한 exception 도 JVM에 의해 처리되지 않는다.