Исключение без трассировки стека в Java
Это, вероятно, очень наивный вопрос.
Раньше я полагал, что Throwable
в Java
всегда содержит трассировку стека. Правильно ли это?
Теперь похоже, что я улавливаю exceptions
без трассировки стека. Имеет ли это смысл? Можно ли исключить исключение без трассировки стека?
Ответы
Ответ 1
Можно поймать Throwable object в Java без трассировки стека:
Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace)
Создает новый, сбрасываемый с помощью указанное подробное сообщение, причина, подавление включено или отключено, и перезаписываемая трассировка стека включена или отключена.
http://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html
Ответ 2
Для Java 6:
Поскольку Java 6 не имеет конструктора Throwable(String message, Throwable cause, boolean enableSuppression,boolean writableStackTrace)
, мы можем подавить заполнение stacktrace, используя нижеприведенную технику (заимствованную из 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
Ответ 3
Для 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 at https://github.com/apache/systemml.
Ответ 4
Самый простой способ подавить stacktrace для любого исключения -
throwable.setStackTrace(new StackTraceElement[0]);
Если у исключения есть причина, вам может потребоваться сделать то же самое рекурсивно.
Это также уменьшает дорогостоящее создание трассировки стека как можно больше
Элемент stacktrace для throwable инициализируется в
Throwable#fillInStackTrace()
который вызывается любым конструктором и, следовательно, его нельзя избежать.
Когда на самом деле используется stacktrace, StackTraceElement [] лениво построен в
Throwable#getOurStackTrace()
что происходит, если поле Throwable.stackTrace еще не установлено.
Устанавливая stacktrace на любое ненулевое значение, избегает построения StackTraceElement [] в Throwable # getOurStackTrace() и как можно меньше снижает эффективность.