Как решить, следует ли добавить исключение в сигнатуру метода или обработать его в методе?

У меня довольно большой опыт работы с Java (в основном математика, пользовательский интерфейс и графика), но я никогда серьезно не работал с такими API, как JDBC или org.w3c.dom где вы в большой степени полагаетесь на обработку проверенных исключений времени выполнения. Поэтому, если я напишу кучу методов, работающих с такими API-интерфейсами, как мне решить, что мне делать с исключениями, должен ли я перехватывать их сразу или добавлять их в сигнатуру метода и таким образом распространять исключения на более высокий уровень фрейма? стек, где они все обрабатываются? Кажется, что все, что я когда-либо хотел бы сделать с этими проверенными исключениями, - это выходить из приложения с ошибкой при каждом обнаружении.

5 ответов

Решение

Как правило, исключения делятся на две группы: 1) тип, из которого вы можете восстановить значимым образом. 2) тип, который указывает на сбой и, возможно, необходимость сообщить об этом (регистрация, возвращение некоторой страницы с ошибкой, отображение диалогового окна и т. Д.).

Первый из них вы обрабатываете близко к месту, где происходит исключение (например, повторите запрос HTTP REST), второй вы предпочтительно обрабатываете в одном месте, а не засоряете ваш код блоками catch.

Связанные с проверкой исключения в веб-приложениях являются хорошим примером типа, который вы не обрабатываете, и вместо этого вы позволяете веб-приложению перехватывать их, а затем сопоставлять их с кодом ответа статуса 400.

Другой пример: Java генерирует проверенное исключение практически для всего, что принимает кодировку символов. Как правило, вы просто хотите передать "utf-8", и, если вы не ошибетесь, это исключение никогда не произойдет. Если это произойдет, это означает, что UTF-8, по-видимому, больше не поддерживается. Я не понимаю, как вы могли бы оправиться от этого значимым образом. Я склонен ловить и отбрасывать их как непроверенные исключения. Они никогда не произойдут, но когда они это сделают, я хочу, чтобы программное обеспечение не работало, за исключением того, что оно где-то регистрируется.

Итак, если какой-то код, который вы используете, генерирует проверенное исключение, вам нужно решить, сможете ли вы восстановить его локально. Если нет, вам нужно решить, должен ли кто-то из стека вызовов хотеть / должен знать или обрабатывать исключение. Если так, добавьте это к своим броскам и переместите решение вверх по стеку вызовов. Если нет, перебросьте его как неконтролируемое исключение и обработайте его где-нибудь централизованно (например, зарегистрируйте его).

На этот вопрос немного сложно ответить.

Допустим, вы идете на рынок, чтобы что-то купить, но у вас нет денег в вашем камердинере. У вас есть банкоматная карточка какого-то банка, но опять же вы не уверены, достаточно ли денег на вашем счете для совершения покупок.

Теперь есть две вещи, которые вы можете сделать здесь. Или,

1) Прежде чем уйти на рынок, вы должны убедиться, что на вашем счету достаточно денег, или

2) Доберитесь до рынка и посмотрите, сможете ли вы купить какие-либо предметы.

Кроме того, в Java есть два типа исключений

Checked Exception which is a sub-class of java.lang.Exception, and 
Unchecked Exception which is a sub-class of java.lang.RuntimeException.

Проверенные исключения могут рассматриваться как синоним первого случая, когда вы ходите по магазинам. Здесь, обнаружив, что у вас недостаточно средств для совершения покупок, вы можете либо позаимствовать его у кого-либо, либо ничего не делать, то есть отказаться от плана покупок на данный момент.

Точно так же Unchecked Exception можно рассматривать как выход на рынок, не зная об остатке на вашем счете. Теперь на счетчике счетов либо ваша транзакция будет успешной, либо она будет отклонена, поскольку на вашем счете недостаточно средств. Здесь также вы можете либо просто извиниться перед владельцем магазина и начать работу, либо позвонить кому-нибудь, чтобы принести необходимые деньги в магазин.

Как видите, то, что вы можете делать в таких ситуациях, полностью зависит от вас.

Аналогично, в программировании на Java нет большой разницы между проверенным и непроверенным исключением и тем, что вы хотите сделать, если возникли исключения, полностью зависит от вашей личной политики / политики организации.

Java-компилятор только предписывает это, что в случае метода, генерирующего Checked Exception, ваш код, использующий этот метод, должен перехватить Exception ИЛИ выбросить его на один уровень вверх. Хотя в случае непроверенных исключений это необязательно.

Возьмем для примера следующий метод, который выдает Проверенное Исключение:

// Here compiler makes sure that you either catch exception OR declare it to be thrown
public void storeDataFromUrl(String url){
    try {
         String data = readDataFromUrl(url); 
    } catch (BadUrlException e) {
         e.printStackTrace();
    }
}

// Here BadUrlException is a subclass of Exception    
public String readDataFromUrl(String url) throws BadUrlException{
    if(isUrlBad(url)){
        throw new BadUrlException("Bad URL: " + url);
    }
    String data = null;
    //read lots of data over HTTP and return it as a String instance.
    return data;
}

Теперь ваш метод storDataFromUrl() может либо перехватить исключение BadUrlException, либо он может объявить его b throw, и в этом случае код, использующий метод storeDataFromUrl(), должен будет сделать то же самое. То есть, либо поймай исключение, либо брось его, чтобы кто-то из вышестоящих имел дело с ним, как ему хотелось бы.

А теперь тот же пример, который выдает исключение Unchecked;

// Here compiler does not force you to either catch exception OR declare it to be thrown
public void storeDataFromUrl(String url){
         String data = readDataFromUrl(url); 
}

// Here BadUrlException is a subclass of RuntimeException    
public String readDataFromUrl(String url) { // Notice, it does not have a throws clause
    if(isUrlBad(url)){
        throw new BadUrlException("Bad URL: " + url);
    }
    String data = null;
    //read lots of data over HTTP and return it as a String instance.
    return data;
}

НЕСКОЛЬКО ПУНКТОВ В большинстве книг рекомендуется использовать проверенные исключения для всех ошибок, из которых приложение может восстановиться, и непроверенные исключения для ошибок, из которых приложение не может восстановиться.

В действительности большинству приложений придется восстанавливать практически все исключения, включая NullPointerException, IllegalArgumentExceptions и многие другие непроверенные исключения. Неудачное действие / транзакция будет прервано, но приложение должно остаться в живых и быть готовым выполнить следующее действие / транзакцию. Обычно законно закрывать приложение только во время запуска. Например, если файл конфигурации отсутствует и приложение не может сделать ничего разумного без него, то законно закрыть приложение.

РЕДАКТИРОВАТЬ: Йо может прочитать эти две статьи для большего понимания по теме: три правила для эффективной обработки исключений и лучшие практики для обработки исключений

Правильное место для обработки исключений полностью зависит от конкретной ситуации. Если вы просто хотите выйти из приложения, не перехватывайте исключения, а объявляйте их в предложении throws.

Однако для серверной программы это не будет хорошей стратегией. Например, вы не хотите, чтобы ваш сервер падал, когда БД недоступна из-за короткой сетевой проблемы.

Что ж, это сложный вопрос. Один из пяти критериев модульности из книги Б.Мейера - Защита. Этот критерий говорит, что если ошибка появляется в классе или модуле, она не должна распространяться в системе дырок. Так что ошибка должен быть изолирован от другого компонента системы.

Поэтому я думаю, что вы должны поймать исключение на низком уровне в системе.

Если исключение указывает на проблему, вызванную внешними источниками, такими как проблема с сетью, неправильный формат xml и т. Д. (Это зависит от типа исключения). тогда вы должны поймать такое исключение, когда вы можете что-то с этим сделать - если это приложение с графическим интерфейсом, то поймать его, где вы можете показать диалоговое окно с ошибкой пользователю - и принять его / ее решение. Если это на сервере, то регистрируйте ошибку - верните ее клиенту. Если исключение связано с программной ошибкой, то в приложении с графическим интерфейсом вы можете войти в систему / или позволить пользователю отправить его по электронной почте пользователю. Для инструмента командной строки я бы разрешил приложению выходить без исключения и выдавать все свои данные на выход, если это приложение с графическим интерфейсом - я бы скорее попытался его перехватить и попытаться восстановить, дав пользователю подсказку о наличии проблемы.

Вы также можете добавить в свою программу глобальный обработчик исключений, который будет автоматически отправлять такие исключения на вашу электронную почту.

Другие вопросы по тегам