Как получить стек вызовов исключения в виде строки
Короткий ответ
Стек вызовов (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() — Возвращает текст сообщения исключения.