Что является альтернативой исключениям для управления потоком?

Я унаследовал Java-приложение, которое обрабатывает запросы и выдает исключение, если оно решает, что запрос должен быть отменен. Исключения были удобны для предыдущего разработчика, потому что они - простой способ выйти из дерева логики, которое больше не применяется (да, goto), и это печатает трассировку стека в журнал, который является хорошей информацией. Похоже, что на форумах и в блогах все согласны с тем, что исключения не должны использоваться для управления потоком, и более половины обработанных запросов отменяются, поэтому они определенно не являются исключительными ситуациями. Одним из аргументов является производительность, которая не применяется, потому что наш исключительный код работает достаточно быстро в течение многих лет. Еще один аргумент в том, что с этим неясно, с чем я согласен. Мой вопрос: какова альтернатива. Единственное, о чем я могу думать, - это чтобы каждый метод возвращал значение true, если обработка должна продолжаться, или false, если это не так. Похоже, это сильно раздуло бы мой код, изменив это:

checkSomething();
checkSomethingElse();

в это:

boolean continueProcessing = false;
continueProcessing = checkSomething();
if (!continueProcessing) {
    return false;
}
continueProcessing = checkSomethingElse();
if (!continueProcessing) {
    return false;
}

И что тогда, если метод должен что-то возвращать? Любое руководство было бы здорово. Мне бы очень хотелось посмотреть, какие "лучшие практики" доступны.

Обновить:

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

5 ответов

В вашем сценарии альтернативы выдают исключение и возвращают результат.

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

  • Создание + throwing + catching исключение примерно на 3 порядка меньше, чем тестирование логического результата.

  • Большая проблема с возвратом кодов состояния заключается в том, что их легко забыть проверить.

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


Не видя реального кода / контекста, я чувствую, что это подходящее место для использования исключений.

См. Как медленно работают исключения Java? для большой дискуссии на эту тему.

ТЛ; др

Разделение концернов, и IMO, вы должны сделать это:

continue = checkSomething() && checkSomethingElse();

или, возможно, есть другие проблемы дизайна в коде.



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

Варианты контроля ошибок:

  1. не сообщать об ошибке. Он либо обрабатывается напрямую функцией, либо не имеет значения
  2. возвращаемое значение
    1. нуль вместо объекта
    2. информация об ошибке (возможно, даже другой тип данных, чем объект, возвращаемый в случае успеха).
  3. переданный аргумент будет использоваться для хранения данных об ошибках.
  4. вызвать событие
  5. вызвать закрытие, переданное функции, если происходит ошибка.
  6. бросить исключение. (Я утверждаю, что это обычно следует делать, только если это не является частью произвольно определенного назначения функции)

Если целью кода является проверка какого-либо состояния, то зная, что состояние ложно, является непосредственно точкой функции. Не выбрасывайте исключение, а возвращайте false.

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

int error = 0;

do
{//try-alt
    error = operation_1(); if(error > 0){break;}
    error = operation_2(); if(error > 0){break;}
    error = operation_3(); if(error > 0){break;}
}while(false);

switch(error) //catch-alt
{
 case 1: handle(1); break;
 case 2: handle(2); break;
 case 3: handle(3); break;   
}

Как насчет

if (!checkSomething()) return false;
if (!checkSomethingElse()) return false;

Нет необходимости в флаге, если вы выходите рано.

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