Исключение без трассировки стека в Java
Это, наверное, очень наивный вопрос.
Раньше я считал, что Throwable
в Java
всегда содержит трассировку стека. Это правильно? Теперь похоже, что я ловлю exceptions
без трассировки стека. Имеет ли это смысл? Можно ли перехватить исключение без трассировки стека?
4 ответа
Можно поймать объект Throwable в Java без трассировки стека:
Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace)
Создает новый бросаемый объект с указанным подробным сообщением, причиной, включенным или отключенным подавлением и включенной или отключенной трассировкой стека для записи.
http://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html
Для Java 6:
Поскольку Java 6 не имеет Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace)
Конструктор, мы можем подавить заполнение стека, используя метод ниже (заимствовано из Scala, узнал из Насколько медленными являются исключения Java?)
class NoStackTraceRuntimeException extends RuntimeException {
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}
Использование такое же: throw new NoStackTraceRuntimeException ()
или это подтипы.
Мы также можем сделать то же самое, расширяя Throwable
:
class NoStackTraceThrowable extends Throwable {
@Override
public synchronized Throwable fillInStackTrace() {
return this;
}
}
Но маленькая загвоздка в том, что вы больше не можете catch
эти исключения с помощью Exception
так как это не подтип Exception
, вместо должен поймать NoStackTraceThrowable
или это подтипы.
Обновление: для некоторых интересных статистических данных о производительности в различных случаях использования, проверьте этот вопрос SO
Для Java 7+ ниже приведен пример исключения, при котором трассировка стека может быть опционально подавлена.
public class SuppressableStacktraceException extends Exception {
private boolean suppressStacktrace = false;
public SuppressableStacktraceException(String message, boolean suppressStacktrace) {
super(message, null, suppressStacktrace, !suppressStacktrace);
this.suppressStacktrace = suppressStacktrace;
}
@Override
public String toString() {
if (suppressStacktrace) {
return getLocalizedMessage();
} else {
return super.toString();
}
}
}
Это можно продемонстрировать с помощью:
try {
throw new SuppressableStacktraceException("Not suppressed", false);
} catch (SuppressableStacktraceException e) {
e.printStackTrace();
}
try {
throw new SuppressableStacktraceException("Suppressed", true);
} catch (SuppressableStacktraceException e) {
e.printStackTrace();
}
Это основано на MLContextException от Apache SystemML, код которого доступен на GitHub по адресу https://github.com/apache/systemml.
Самый простой способ подавить трассировку стека в любом Исключении -
throwable.setStackTrace(new StackTraceElement[0]);
Если у исключения есть причина, вам может потребоваться сделать то же самое рекурсивно.
Это также максимально снижает стоимость создания трассировки стека.
Трассировка стека для броска инициализируется в
Throwable#fillInStackTrace()
, который вызывается любым конструктором и, таким образом, его нельзя избежать. Когда на самом деле используется трассировка стека, StackTraceElement[] лениво создается в
Throwable#getOurStackTrace()
что происходит только в том случае, если поле Throwable.stackTrace еще не было установлено.
Установка для stacktrace любого ненулевого значения исключает создание StackTraceElement[] в Throwable#getOurStackTrace() и максимально снижает снижение производительности.
Как указано в ответе NG., Если вы сначала видите трассировку стека, но затем она исчезает для того же исключения, вы, скорее всего, видите эффекты оптимизации JVM. В этом случае следующие вопросы очень похожи.
Повторяющееся исключение без трассировки стека - как сбросить?
NullPointerException в Java без StackTrace
Вы можете отключить эту функцию JVM, но я бы рекомендовал оставить ее включенной и работать над предотвращением ошибки в первую очередь или ее перехватом и более изящной обработкой.