Подтвердить что ты не робот

Это злоупотребление попыткой/наконец?

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

Вариант A: несколько возвратов, повторяющийся блок кода

public bool myMethod() {
    /* ... code ... */

    if(thisCondition) {
        /* ... code that must run at end of method ... */
        return false;
    }

    /* ... more code ... */

    if(thatCondition) {
        /* ... the SAME code that must run at end of method ... */
        return false;
    }

    /* ... even more code ... */

    /* ... the SAME CODE AGAIN that must run at end of method ... */
    return lastCondition;
}

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

Опция B немного более приемлема? Я чувствую, что могу злоупотреблять попыткой/наконец, и я надеюсь, что есть что-то совершенно другое, что я должен делать.

Вариант B: несколько возвратов, блок try/finally (без блоков/исключений catch)

public bool myMethod() {
    try {
        /* ... code ... */

        if(thisCondition) {
            return false;
        }

        /* ... more code ... */

        if(thatCondition) {
            return false;
        }

        /* ... even more code ... */

        return lastCondition;
    } finally {
        /* ... code that must run at end of method ... */
    }
}

Наконец, вариант C - лучшее решение в моей книге, но моей команде не нравится этот подход по любой причине, поэтому я ищу компромисс.

Вариант C: одиночный возврат, условные блоки

public bool myMethod() {
    /* ... code ... */

    if(!thisCondition) {
        /* ... more code ... */
    }

    if(!thisCondition && !thatCondition) {
        /* ... even more code ... */
    }

    /* ... code that must run at end of method ... */
    return summaryCondition;
}

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

4b9b3361

Ответ 1

Исключения должны быть исключительными, поэтому мне не нравится вариант B, если нет других исключений (примечание для downvoters - я не говорю, что, наконец, неверно, что я предпочитаю не иметь его, если нет исключений - если у вас есть причины, пожалуйста, прокомментируйте)

Если код всегда необходим, как о рефакторинге на 2 функции

public bool myMethod() {
    bool summaryCondition = myMethodWork();
    // do common code
    return summaryCondition;
}

private bool myMethodWork() {
   /* ... code ... */

    if(thisCondition) {
        return false;
    }

    /* ... more code ... */

    if(thatCondition) {
        return false;
    }

    /* ... even more code ... */

    return lastCondition;
}

Ответ 2

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

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

Лично я переписал этот метод в стиле с одной точкой возврата. Не потому, что я религиозно соглашаюсь с этой идеей (я этого не делаю), а потому, что она лучше всего подходит для этих кодов конца кода.

Когда этот код оказывается чрезмерно сложным (и это очень реальная возможность), то пришло время реорганизовать метод, извлекая один или несколько методов.

Самый простой рефакторинг будет примерно таким:

public boolean  myMethod() {
    boolean result = myExtractedMethod();
    /* ... code that must run at end of method ... */
    return result;
}

protected boolean myExtractedMethod() {
    /* ... code ... */

    if(thisCondition) {
        return false;
    }

    /* ... more code ... */

    if(thatCondition) {
        return false;
    }

    /* ... even more code ... */
    return lastCondition;
}

Ответ 3

Это идеальное место для GOTO

* утки *

Ответ 4

Если код нужно запустить, даже если есть Exception, то finally - не только хороший выбор, но и обязательный. Если это не так, finally не требуется. Похоже, вы хотите найти формат, который "выглядит" лучше всего. Но здесь здесь немного больше.

Ответ 5

Решение не является оптимальным, поскольку оно правильно кодирует последовательность выполнения, которую вы пытаетесь выполнить.

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

public bool myMethod() { 
    boolean  rc = lastCondition; 

    /* ... code-1 ... */ 

    if (thisCondition) { 
        rc = false;
    } 
    else {  
        /* ... code-2 ... */ 

        if (thatCondition) { 
            rc = false;
        } 
        else {  
            /* ... code-3 ... */ 
            rc = ???;
        }  
    }

    /* ... the code that must run at end of method ... */ 
    return rc;  
}

Упрощение дает код:

public bool myMethod() { 
    boolean  rc = false; 

    /* ... code-1 ... */ 

    if (!thisCondition) { 
        /* ... code-2 ... */ 

        if (!thatCondition) { 
            /* ... code-3 ... */ 
            rc = lastCondition;
        }  
    }

    /* ... the code that must run at end of method ... */ 
    return rc;  
}

Упрощенный код также показывает то, что вы на самом деле пытаетесь достичь: вы используете условия теста, чтобы избежать выполнения кода, поэтому вы, вероятно, должны выполнять этот код, когда условия ложны, а не что-то делать, когда они верны.

Чтобы ответить на вопрос о блоках try-finally: Да, вы можете злоупотреблять ими. Ваш пример недостаточно сложный, чтобы гарантировать использование try-finally. Однако, если это было бы сложнее, возможно.

Посмотрите, как я возьму его по адресу: Перейти к заявлению, считающемуся вредным: ретроспектива, "Обработка исключений" .

Ответ 6

Как разбить его немного больше, чтобы дать что-то большее (извиняясь за то, что я не использовал логические операторы Java довольно давно) вот так:

public bool findFirstCondition()
{
   // do some stuff giving the return value of the original "thisCondition".
}

public bool findSecondCondition()
{
   // do some stuff giving the return value of the original "thatCondition".
}

public bool findLastCondition()
{
   // do some stuff giving the return value of the original "lastCondition".
}

private void cleanUp() 
{
   // perform common cleanup tasks.
}


public bool myMethod() 
{ 


   bool returnval = true;
   returnval = returnval && findFirstCondition();
   returnval = returnval && findSecondCondition();

   returnval = returnval && findLastCondition();
   cleanUp();
   return returnval; 
}

Ответ 7

Не злоупотребляйте try/finally, если вам не нужно вырваться из внутренних циклов. Нарушение do/while.

bool result = false;
do {
  // Code
  if (condition1) break;
  // Code
  if (condition2) break;
  // . . .
  result = lastCondition
} while (false);

Ответ 8

Использование try/finally для управления потоком кажется мне полезным, используя GOTO.

Ответ 9

Есть ли причина, по которой вы не можете просто сохранить возвращаемое значение и выпасть из if?

   bool retVal = true;
   if (retVal && thisCondition) {
   }

   /* more code */

   if ( retVal ) {
     /* ... code that must run at end of method, maybe inside an if or maybe not... */

   }
   return retVal;

Ответ 10

IMO идея состоит в том, чтобы поместить блок try на малую часть кода (например, вызов метода), который может вызывать известное исключение (например, чтение из файла, чтение int до String)), Поэтому размещение блока try по всему коду метода на самом деле не подходит, если вы на самом деле не ожидаете, что каждый код условия if потенциально может передать один и тот же набор исключений. Я не вижу смысла использовать блок try только ради использования finally.

Если я не ошибаюсь, добавление больших фрагментов кода внутри try также делает его намного медленнее, но не уверен, что это верно в последних версиях Java.

Лично я бы пошел с Option C. Но у меня нет ничего против варианта A.

Ответ 11

Если код, который должен выполняться в конце метода, использует локальные переменные метода, вы можете извлечь его в метод, например:

public boolean myMethod() {
    /* ... code ... */

    if(thisCondition) {
        return myMethodCleanup(false);
    }

    /* ... more code ... */

    if(thatCondition) {
        return myMethodCleanup(false);
    }

    /* ... even more code ... */

    return myMethodCleanup(lastCondition);
}

private boolean myMethodCleanup(boolean result) {

    /* ... the CODE that must run at end of method ... */
    return result;
}

это все равно выглядит не очень красиво, но лучше, чем использование goto-подобных конструкций. Чтобы убедить своих товарищей по команде в том, что решение с 1 возвратом может быть не так уж плохо, вы также можете представить версию, используя 2 do { ... } while (false); и break (* evil grin *.)