JavaRush /Java блог /Архив info.javarush /Типичные ошибки в обработке исключений
Ve4niY
14 уровень

Типичные ошибки в обработке исключений

Статья из группы Архив info.javarush
Исключение - это нарушение нормального хода выполнения Java (или любой другой) программы. Это нарушение может произойти из-за нарушения доступа к памяти, делении на ноль, проблемы инициализации, выполнении запрещенной инструкции или любой другой фатальной ошибки. Java способен обрабатывать все такие нежелательные сценарии элегантно, но когда дело доходит до использования этих возможностей Java разработчиками, может возникнуть несколько проблем. В этой статье я не собираюсь обсуждать, как работает обработка исключений (Exception Handling) в Java. Я предполагаю, что читатель уже знаком с иерархией исключений, проверяемыми исключениями (checked exceptions), непроверяемыми исключениями (unchecked exceptions), исключительными рабочими ситуациями при выполнении программы (runtime exceptions). Здесь мы обсудим наиболее распространенные ошибки, которых следует избегать.
Заинтересованные стороны в исключениях
Всякий раз, когда поток выполнения прерывается, информация об этом должна вернуться к исполнителю программы. Этот поток может стартовать с экрана, с пакетной задачи или любым другим способом. Все эти триггеры ожидают каких либо нарушений в потоке для передачи сообщения определенного формата. Триггер на основе экрана может мягко сообщить нам, что есть некоторые технические проблемы и следует обратиться за помощью и консультацией в службу поддержки. Пакетные процессы, или автономные Java-программы могут ожидать, что отчет об ошибке предстанет в виде какого-либо журнала, совершенно непонятного конечному пользователю. Но деловые люди должны получать сообщения на понятном им языке. Страшный NullPointerException в головах юзеров сильно раздражает. Иногда эти ошибки - следствие неправильного использования программы, но иногда - проблемы, требующие исправления. Второй важной заинтересованной стороной является человек, которому придется решать проблемы, возникнувшие с появлением исключений. Этот человек не может наблюдать фактическое исполнение программы во время возникновения исключения. Он будет опираться на две вещи - во-первых, на информацию, предоставленную пользователем, у которого возникла проблема, а во-вторых - на своего рода журнал, генерируемый при появлении исключения. К тому же, человек, который будет анализировать проблему - не тот же самый человек, который написал программу, и, следовательно, разработчик программы должен предоставить достаточно информации для анализа. Единственный способ общения между разработчиком программы и ее отладчиком - журнал. Кроме того, иногда из-за соображений безопасности, лог журнала иногда не могут содержать всех фактических деталей выполнения программы, когда появилось исключение. Давайте рассмотрим возможные ошибки в обработке исключений. Некоторые из них выглядят довольно глупо, но есть люди. которые не обращают на них внимание, пока эти ошибки не приводят к проблемам.
Пустой блок исключения
Это одна из наиболее нежелательных ошибок в обработке исключительных ситуаций. В этом случае исключение просто игнорируется. Решение не содержит ничего, кроме линии комментария покинуть исключение. try{ }catch(SQLException sqe){ // do nothing } В некоторых редких случаях, например, в финальном блоке, при отключении базы данных, допустимо появление исключений . В этом случае они могут быть проигнорированы. try{ }catch(SQLException sqe){ ... ... }finally{ try{ conn.close(); }catch(Exception e){ //leave it. } }
Неправильное обобщение сообщения об исключении
Этот момент носит субъективный характер. После перехвата исключения, вы можете сообщить об этом конечному пользователю в виде дружеского послания. При этом вполне возможно, что детали исходного сообщения будут потеряны при преобразовании исходных сообщений в одно общее. Сообщение должно довести надлежащую информацию до конечного потребителя так, чтобы, связавшись с командой поддержки, для предоставления информации пользователю достаточно было войти в соответствующий журнал. try{ File file = new File(""); file.getCanonicalPath(); }catch(IOException ioe){ throw new Exception("File Processing Failed",ioe); } В многоуровневом приложении каждый слой ловит исключения и создает новый тип исключения. Иногда абсолютно необходимо при этом преобразовать исключение определенного типа: - Data Access Layer -> создает DataAccessException - Business Implementation Layer -> создает BusinessException - Application Service Layer -> создает ApplicationServiceException Все выглядит логично, не так ли? Здесь нам, возможно, придется выбирать между ApplicationServiceException и BusinessException, поскольку оба могут представлять одну и ту же информацию. Одно из этих преобразований исключений выглядит лишним.
Уничтожение класса StackTrace
В процессе трансформации исключения в новый специальный тип может пропасть трассировка стека, и тогда отслеживание фактической причины исключения становится кошмаром наяву. В коде ниже вы можете увидеть, как новое исключение создается без получения какой-либо информации от исходного исключения. try{ File file = new File(""); file.getCanonicalPath(); }catch(IOException ioe){ throw new MyException("Problem in data reading."); }
Перезапись причины исключения
Каждое сообщение об исключении несет в себе информацию о причине исключения. Однако при создании нового исключения информация о старом может быть безвозвратно удалена. Это похоже на приведенный выше пример, где StackTrace может быть удален из-за появления нового исключения.
Отсутствие поиска определенных исключений
Иногда разработчики любят действовать наверняка в обработке исключений. Иногда это легко осуществить. Но ловить java.lang.Exception вместо конкретного исключения не является приемлемым. try{ File file = new File(""); file.getCanonicalPath(); }catch(Exception exe){ throw new MyException("Problem in data reading."); }
Ненужныe catch и throw
Перехватывайте исключения, если вы хотите преобразовать их в другой тип, либо если это поможет вам добавить какую-либо информацию в сообщение об исключении для конечного пользователя или аналитика. В противном случае просто выбрасывайте их дальше в сигнатуре метода (с помощью throws)вместо их перехватывания.
Ловля RuntimeException
Я рекомендовал бы избегать перехватывания RuntimeException. Вместо этого лучше ловить конкретные исключения и лечить их.
Поиск непроверяемых исключений
Это спорная тема - ловить непроверяемые исключения или нет. NullPointerException и ArrayIndexOutOfBound могут быть лучшими примерами непроверяемых исключений. Вместо того, чтобы ловить эти исключения, вы можете изменить код для обработки этих сценариев. Например чтобы избежать NullPointerException, обеспечить инициализацию всех переменных, чтобы избежать исключений ArrayIndexOutOfBound, определить массив правильной длины и т.д.
Проблемы, относящиеся к регистрации исключений
Журнал поможет второму заинтересованному, то есть человеку анализирующему проблемы. Иногда разработчик перебарщивает с файлами логов, и журналы создаются на каждом уровне приложения. Журнал должен регистрировать исключение на том уровне, на котором оно произошло. Оптимальным кажется вывод предупреждения, что произошло исключение, с предложением остановить или продолжить выполнение программы, и обязательного протоколирования исключения в журнале.
Исключение для управления потоком
Исключение является нарушением нормального течения работы программы, а это значит что нужно нужно прервать этот поток и проинформировать об этом конечного пользователя. Если мы добавим вызов метода, которая является альтернативным потоком, это приведет к огромным проблемам обслуживания. try{ myObject.getValue(); }catch(NullPointerException npe){ alternateMethod(); }
Повсеместное использование java.lang.Exception
Не лучшая идеей видится и повсеместное использование для любого исключения java.lang.Exception. Вместо этого лучше использовать специфические исключения приложения, или наиболее подходящие стандартные Java исключения. Исходная статья: Common Mistakes in Exception Handling Переведено и озвучено: Ve4niY
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
SergioShapoval Уровень 41
1 июля 2015
Весьма поучительная статья применимая в реальной практике, либо полученная собственными шишками,
спасибо!