Недавно я столкнулся с некоторой проблемой исключений в java, которая напомнила мне типичную идиому, рекомендованную Брюсом Экелом :
Преобразование отмеченных исключений в исключение
Настоящая проблема в том, что когда вы пишете тело обычного метода, и вы вызываете другой метод и понимаете: «Я понятия не имею, что здесь делать с этим исключением, но я не хочу проглотить его или напечатать какое-нибудь банальное сообщение."За исключением цепочек, новое и простое решение предотвращает себя.Вы просто «оборачиваете» проверенное исключение внутри RuntimeException , передавая его конструктору RuntimeException , например:
try {
// ... to do something useful
} catch (IDontKnowWhatToDoWithThisCheckedException e) {
throw new RuntimeException(e);
}
Это кажется идеальным решениемесли вы хотите «отключить проверенное исключение - вы его не проглотите, и вам не нужно включать его в спецификацию исключений вашего метода, но из-за цепочки исключений вы не потеряете никакой информации из исходного исключения.
Этот метод предоставляет возможность игнорировать исключение и позволить ему пузыриться в стеке вызовов без необходимости писать предложения try-catch и / или спецификации исключений.
Однако яобнаружил, что в некоторых случаях это не сработало, как показано здесь:
package exceptions;
// How an exception can be lost
class VeryImportantException extends Exception {
@Override
public String toString() {
return "A very important exception";
}
}
class HoHumException extends Exception {
@Override
public String toString() {
return "A trivial exception";
}
}
public class LostMessage {
void f() throws VeryImportantException {
throw new VeryImportantException();
}
void dispose() throws HoHumException {
throw new HoHumException();
}
public static void main(String[] args) {
try {
LostMessage lm = new LostMessage();
try {
lm.f();
} catch (VeryImportantException e) {
throw new RuntimeException(e);
} finally {
lm.dispose();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}/* Output:
Exception in thread "main" java.lang.RuntimeException: A trivial exception
at exceptions.LostMessage.main(LostMessage.java:36)
Caused by: A trivial exception
at exceptions.LostMessage.dispose(LostMessage.java:23)
at exceptions.LostMessage.main(LostMessage.java:33)
*///:~
Как показал вывод, второе исключение полностью стирает первое. В трассировке стека исключений нет записи первого исключения, что может значительно усложнить отладку в реальных системах. обычно это первое исключение, которое вы хотитесм. для диагностики проблемы.
Джошуа Блох рекомендует try-with-resource способ, которым ресурс должен реализовать интерфейс AutoCloseable , который процесс несколько сложен.
Итак, мой вопрос таков: есть ли способ, которым я могу использовать, чтобы исключение не потеряло информацию о трассировке стека при подходе Брюса Экеля ?