Я не уверен, задавался ли этот вопрос раньше, но мне всегда было интересно, почему каждый экземпляр Throwable
, если только метод fillInStackTrace
не переопределен / подавлен, заполняет свою трассировку стека в конструкторе во время его созданияпо умолчанию. Рассмотрим следующий код:
final class ThrowableTest {
private ThrowableTest() {}
public static void main(final String... args) throws Throwable { throw go(); }
private static Throwable go() { return goDeep(); }
private static Throwable goDeep() { return goDeeper(); }
private static Throwable goDeeper() { return goEvenDeeper(); }
private static Throwable goEvenDeeper() { return new Throwable(); }
}
Выполнение приведенного выше кода приведет к следующему выводу:
Exception in thread "main" java.lang.Throwable
at ThrowableTest.goEvenDeeper(scratch.java:9)
at ThrowableTest.goDeeper(scratch.java:8)
at ThrowableTest.goDeep(scratch.java:7)
at ThrowableTest.go(scratch.java:6)
at ThrowableTest.main(scratch.java:5)
Я бы нашел следующую гипотетическую трассировку стека более интуитивной (если предположить, что метод fillInStackTrace
не переопределяется, и конструктор Throwable
не вызывает его в таком «специальном» JRE):
Exception in thread "main" java.lang.Throwable
at ThrowableTest.main(scratch.java:5)
Мне интересно: почему трассировка стека заполнена в конструкторе (в его простейшем сценарии), ачем на сайте исключения, использующем throw
? Если я не ошибаюсь, есть некоторые сценарии, когда fillInStackTrace
может использоваться для настройки исключения (повторного) выброса, а throw
, как описано, переписывает трассировку стека в текущую. Но если это так, оператор throw
(и инструкция athrow
) может проверить, установлена ли для трассировки стека исключительная ситуация null
, прежде чем заполнять ее самостоятельно (при условии, что выбрасывается что-то отличное от экземпляра * 1020). * не определено, как описано в спецификации). Какой дизайн был за этим стоит?