Java: исключения как поток управления? - PullRequest
10 голосов
/ 10 октября 2009

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

public static findStringMatch(g0, g1) {

    int g0Left = -1;
    int g0Right = -1;
    int g1Left = -1;
    int g1Right = -1;

//if a match is found, set the above ints to the proper indices
//...
//if not, the ints remain -1

        try {
            String gL0 = g0.substring(0, g0Left);
            String gL1 = g1.substring(0, g1Left);

            String g0match = g0.substring(g0Left, g0Right);
            String g1match = g1.substring(g1Left, g1Right);

            String gR0 = g0.substring(g0Right);
            String gR1 = g1.substring(g1Right);

            return new StringMatch(gL0, gR0, g0match, g1match, gL1, gR1);
        }
        catch (StringIndexOutOfBoundsException e) {
            return new StringMatch(); //no match found
        }

Таким образом, если совпадений не найдено, целые числа будут равны -1. Это вызовет исключение, когда я попытаюсь взять подстроку g0.substring(0, -1). Затем функция просто возвращает объект, указывающий, что совпадение не найдено.

Это плохая практика? Я мог бы просто проверить каждый индекс вручную, чтобы увидеть, все ли они равны -1, но это похоже на дополнительную работу.

UPDATE

Я удалил блок try-catch и заменил его следующим:

    if (g0Left == -1 || g0Right == -1 || g1Left == -1 || g1Right == -1) {
        return new StringMatch();
    }

Что лучше: проверить, равна ли каждая переменная -1, или использовать логическое значение foundMatch, чтобы отслеживать и просто проверить это в конце?

Ответы [ 4 ]

17 голосов
/ 10 октября 2009

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

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

10 голосов
/ 10 октября 2009

Я провел некоторое тестирование по этому вопросу. На современных JVM это фактически не сильно влияет на производительность во время выполнения (если вообще). Если вы запускаете с включенной отладкой, это значительно замедляет работу.

См. Следующее для подробностей

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

6 голосов
/ 19 февраля 2010

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

Я борюсь с немного другим уклоном по этой проблеме прямо сейчас во время какого-то устаревшего рефакторинга кода.

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

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

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

На мой взгляд, вы могли бы сделать это, если вы поместите блоки try / catch очень ; но я думаю, что это дурная привычка, которая может привести к тому, что код, который очень легко будет неверно интерпретировать, поскольку вызывающий код будет интерпретировать любое выброшенное исключение как сообщение типа 'GOTO' , изменяя ход программы. Я боюсь, что, хотя этот случай не попадает в эту ловушку, выполнение этого часто может привести к привычке кодирования, ведущей к кошмару, в котором я сейчас живу.

И этот кошмар не приятен.

6 голосов
/ 10 октября 2009

Да, это плохая практика, особенно когда у вас есть способ избежать исключения (проверьте длину строки, прежде чем пытаться проиндексировать ее). Блоки try и catch предназначены для отделения «нормальной» логики от «исключительной» и логики ошибок. В вашем примере вы распространили «нормальную» логику в блок исключений / ошибок (поиск совпадений не является исключением). Вы также неправильно используете substring, так что вы можете использовать ошибку, которую она выдает, как поток управления.

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