Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Как получить стек вызовов исключения в виде строки

Короткий ответ

Стек вызовов (stack trace) показывает цепочку методов, которая привела к ошибке. printStackTrace() может писать его в StringWriter, откуда стек забирается строкой:

void main() {
    try {
        Integer.parseInt("abc");
    } catch (NumberFormatException e) {
        var writer = new StringWriter();
        e.printStackTrace(new PrintWriter(writer));
 
        String trace = writer.toString();
        IO.println(trace.lines().count() > 1);
        IO.println(trace.lines().findFirst().orElseThrow());
    }
}

Результат:

true
java.lang.NumberFormatException: For input string: "abc"

Место ошибки

getStackTrace() возвращает массив элементов стека. Последний в цепочке вызов — первый элемент:

void check(int age) {
    if (age < 0) {
        throw new IllegalArgumentException("age < 0");
    }
}
 
void main() {
    try {
        check(-1);
    } catch (IllegalArgumentException e) {
        StackTraceElement top = e.getStackTrace()[0];
        IO.println(top.getMethodName() + " at line " + top.getLineNumber());
    }
}

Результат:

check at line 3

В журнал

Логгеры принимают исключение отдельным аргументом и сами печатают стек. Например, с System.Logger:

// src/main/java/shop/OrderService.java
private static final System.Logger LOG = System.getLogger(OrderService.class.getName());
 
void save(Order order) {
    try {
        repository.save(order);
    } catch (RuntimeException e) {
        LOG.log(System.Logger.Level.ERROR, "Cannot save order " + order.id(), e);
        throw e;
    }
}

Частая ошибка

Сохранять в журнал только e.getMessage(). У многих исключений сообщение пустое или неинформативное, а без стека не понять, где произошла ошибка:

void main() {
    try {
        Object value = null;
        value.toString();
    } catch (NullPointerException e) {
        IO.println(e.getClass().getSimpleName() + ": " + e.getMessage());
    }
}

Результат:

NullPointerException: Cannot invoke "Object.toString()" because "<local1>" is null

Сообщение здесь есть, но в нём нет ни имени метода, ни номера строки. Передавайте в логгер всё исключение целиком.

Функции из этого ответа

  • Throwable.printStackTrace() — Печатает исключение и цепочку вызовов, которая к нему привела, в поток ошибок.
  • Throwable.getMessage() — Возвращает текст сообщения исключения.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.