#java #design-patterns #exception #exception-handling
#java #шаблоны проектирования #исключение
Вопрос:
Я работаю над большим веб-приложением Java с Spring, Hibernate и некоторыми другими библиотеками, включая Apache log4j для ведения журнала. Один из моих текущих проектов — переписать большое количество исключений в устаревших областях (которые я не писал!) кода, Чтобы предоставить более разумную информацию. Типичный блок исключений выглядит следующим образом:
try {
//Some Hibernate business here
}
catch (Exception e) { //Yes, Exception. That's not just me being general. I find this especially frustrating.
log4j.error("Fail to XXXXXX"); //again, real
throw new MyException();
}
Как вы можете догадаться, это создает некоторые сложные журналы. Я ищу стандартный способ получить лучшую информацию из этих исключений. Большинство из них переносят вызовы гибернации, если это помогает. Вот типичный блок, похожий на тот, который я только что написал:
try {
myList.add( ((myClass) commonService.getRecordByTableId(myClass.class, ID)).toString() );
} catch (ServiceException e) {
log4j.error("Failed to retrieve record from table myClass for id " ID);
e.printStackTrace();
}
Здесь я извлекаю запись из базы данных и добавляю ее в список. В блоке catch я регистрирую то, что, по моему мнению, является разумным сообщением о том, что try
делает блок, и печатаю трассировку стека. Итак, мой вопрос: есть ли что-нибудь еще, что я мог / должен делать, в общем, чтобы получить лучшую информацию для диагностики ошибок?
Ответ №1:
При обработке исключений ведение журнала и повторное выбрасывание является популярным антишаблоном. Вы не должны этого делать. Вам нужно решить, перехватывать ли исключение, затем правильно обрабатывать его (включая ведение журнала) или не перехватывать его и разрешить ему переходить на более высокие уровни (или повторно использовать его / обернуть его в исключение во время выполнения, если это было проверенное исключение).
Если вы это сделаете (log rethrow), то вышестоящий код не сможет узнать, что вы уже зарегистрировали исключение, и поэтому одно и то же исключение может регистрироваться дважды или более, в зависимости от того, через сколько слоев должно пройти исключение, и какой уровень произвольно решает регистрировать иповторно выбросьте его. Это сделает чтение журналов и их устранение полным кошмаром.
Также вы можете утверждать, что выбрасывание и перехват исключений являются дорогостоящими операциями, весь этот перехват и повторное перемещение не способствуют вашей производительности во время выполнения.
Итак, если вы решите фактически обработать исключение, то проглатывать его — неправильный способ (даже если вы регистрируете какое-то сообщение). По крайней мере, вам нужно зарегистрировать трассировку:
log4j.error("Failed to retrieve record from table myClass for id " ID, e);
Комментарии:
1. 1. Я бы тоже дал больше очков, если бы мог. Я так устал видеть трассировку стека с несколькими «отголосками» перед ней.
2. Да, я тоже. Удивительно, как много «серьезных» разработчиков считают ведение журнала и повторное перемещение достаточно хорошей обработкой для большинства исключений.
3. 1, хороший вызов. Многое из того, что произошло в этом проекте, меня очень огорчает, и я пытаюсь привести это в форму. : D
4. Кроме того, мне нравится слово «анти-шаблон».
Ответ №2:
printStackTrace()
не добавляет трассировку в ваш журнал. Отправка исключения в log4j напечатает его в вашем файле журнала, где контекст имеет смысл:
log4j.error("Failed to retrieve record from table myClass for id " ID, e);
Ответ №3:
Несколько вещей в дополнение к тому, что упоминали другие:
- Используйте различные уровни ведения журнала: информация; предупреждение; и т.д.
- Следуя # 1, я бы отказался от этих вызовов printStackTrace(). Если вы хотите регистрировать ошибки в консоли, делайте это через регистратор. Таким образом, вы получаете преимущества фильтрации уровней даже для консоли.
Ответ №4:
да, в самом первом блоке это должно быть так:
try {
//Some Hibernate business here
}
catch (Exception e) { //Yes, Exception. That's not just me being general
log4j.error("Fail to XXXXXX", e); //again, real
throw new MyException(e);
}
Java позволяет создавать цепочки исключений, поэтому вы должны это делать. Кроме того, при использовании Log4J вы также можете отправить исключение, чтобы оно также печатало трассировку стека исключений в ваших журналах.