Является ли try / catch для каждого отдельного оператора, который выдает исключение, антипаттерном? - PullRequest
8 голосов
/ 17 августа 2011

В настоящее время я рассматриваю Java-код коллег и вижу много случаев, когда каждое отдельное утверждение, которое может вызвать исключение, инкапсулируется в свой собственный try / catch. Где все блоки catch выполняют одну и ту же операцию (эта операция не относится к моему вопросу).

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

Таким образом, try / catch для каждого отдельного оператора, который выбрасывает и исключение считается анти-паттерном, и какой аргумент поддерживает это?


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

public int foo()
{
    int x, y = 7;

    try
    {
        x = bar(y);
    }
    catch(SomeException e)
    {
        return 0;
    }

    try
    {
        y = baz(x,y);
    }
    catch(SomeOtherException e)
    {
        return 0;
    }

    /* etc. */

    return y;
}

(Предположим, что здесь уместно уловить оба исключения, т. Е. Мы знаем, что с ними делать, и уместно вернуть 0 в обоих случаях.)

Ответы [ 6 ]

6 голосов
/ 17 августа 2011

Я не могу предоставить вам авторитетный источник, но это основные принципы обработки исключений:

  • исключения должны быть зафиксированы в том месте, где их можно правильно обработать, и
  • Вы не должны глотать исключения - всегда должна быть (по крайней мере) трассировка исключительной ситуации, поэтому минимум должен регистрировать ее, чтобы, по крайней мере, разработчики имели возможность заметить, что случилось что-то плохое. Что приводит к третьему пункту:
  • исключения должны использоваться только для сигнализации об исключительных плохих событиях, а не для контроля потока программы.

Есть много более ранних постов на SO, посвященных этому, например Лучшие практики для управления исключениями в JAVA или C # .

3 голосов
/ 17 августа 2011

Моей первоначальной реакцией было то, что это плохо. (Также у меня изначально были аргументы о перехвате исключений в целом, но я убрал их, чтобы сосредоточиться на примере, приведенном в вопросе.) Трудно судить о возврате 0 для исключения, поскольку неизвестно, что делают bar и baz, и что представляют собой исключения , Если вызывающей стороне действительно не нужно знать, что что-то пошло не так, и вызывающей стороне не нужно различать возвращаемое значение как условие ошибки и возвращаемое значение как данные, то это нормально. С другой стороны, если возникают исключения из-за проблем с недоступностью ресурсов, лучше потерпеть неудачу быстрее, чем пытаться бороться.

Я сомневаюсь, что это хорошо, потому что если для этого кода разумно возвращать 0 в исключении, было бы разумно, по крайней мере, разумно, чтобы bar и baz возвращали 0 в первую очередь.

Обращаться к исключению перехвата для каждого отдельного оператора в целом (в отличие от немедленного возврата со значением по умолчанию, как в примере), это плохо, потому что, как только вы выбросили исключение, что-то пошло не так, и ваш метод или объект может быть в плохом состоянии. Цель обработки исключений состоит в том, чтобы иметь возможность избежать контекста, в котором что-то пошло не так, и вернуться в место с известным состоянием. Если бы ловить каждое исключение и допускать ошибки, все наши языки поддерживали бы «On Error Resume Next».

2 голосов
/ 17 августа 2011

Дьявол кроется в деталях. Это зависит от контекста. Когда вы ожидаете эти исключения? Например, если SomeException указывает на довольно распространенное нарушение бизнес-правила, и в этом контексте допустимо возвращать 0, я могу видеть приведенный выше код вполне допустимым. Наличие блока try..catch близко к методу, который вызывает его, не так уж и плохо, так как определить, какой метод может вызвать исключение, может оказаться непростой задачей, если обернуть 10 методов в один гигантский try..catch.

Однако, если это исключения, которые указывают на то, что что-то пошло не так, и SomeException не должно возникать, то возвращение «0», когда скрывается магический индикатор ошибки, может потенциально скрыть, что что-то пошло не так, это может быть кошмар обслуживания, чтобы узнать, где возникла проблема.

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

Не регистрировать исключение также не обязательно плохо. Если исключение возникает очень часто и не является показателем того, что что-то пошло не так, то вам не нужно каждый раз записывать в журнал, иначе вы «отравите журналы» (т. Е. Потому что, если 99% записей журнала связаны с SomeException, то какова вероятность того, что вы пропустите исключение в журнале и / или у вас закончится свободное место на диске, потому что вы получаете сообщение журнала 50 000 раз в день).

0 голосов
/ 17 августа 2011

Я думаю, что ваш коллега прочитал старую лучшую практику J2EE"Поймайте исключение как можно ближе к его источнику". а потом он немного переборщил с этим.

0 голосов
/ 17 августа 2011

Я на самом деле не думаю, что это анти-паттерн, как таковой. Но это определенно не чистый код, который почти так же плох.

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

0 голосов
/ 17 августа 2011

Для данного примера аргументом является то, что он является избыточным. Вам нужен только один try/catch блок с одним return null.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...