Рекурсия в блоке try-catch-finally: как вызвать блок finally только один раз при исходном вызове функции? - PullRequest
0 голосов
/ 19 апреля 2019

Допустим, у меня есть функция с именем foo (). В foo () есть блок try-catch-finally. Внутри блока catch функция foo () вызывается рекурсивно.

Мой вопрос:

Как сделать так, чтобы блок finally выполнялся только один раз при исходном вызове функции?

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

private Integer recursion_counter = 0;

public ReturnType foo(){
    ReturnType returnType = new ReturnType();

    try{
        // Try to do something...
        returnType = doSomething();
    } catch (Exception e){
        if (recursion_counter == 5) {
            // Issue not fixed within 5 retries, throw the error
            throw e;
        } else {
            recursion_counter++;
            attemptToFixTheIssue();
            returnType = foo();
            return returnType;
        }
    } finally{
        resetRecursionCounter();
    }

    return returnType;
}

private void resetRecursionCounter(){
    recursion_counter = 0;
}

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

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

Ответы [ 3 ]

2 голосов
/ 09 июля 2019

Просто не используйте рекурсию для такой задачи:

public ReturnType foo() {
    for(int attempts = 0; ; attempts++) {
        try {
            // Try to do something...
            return doSomething();
        } catch(Exception e) {
            if(attempts == 5) {
                // Issue not fixed within 5 retries, throw the error
                throw e;
            } else {
                attemptToFixTheIssue();
            }
        }
    }
}

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

public ReturnType foo() {
    return foo(0);
}

private ReturnType foo(int recursionCounter) {
    try {
        // Try to do something...
        return doSomething();
    } catch (Exception e){
        if (recursionCounter == 5) {
            // Issue not fixed within 5 retries, throw the error
            throw e;
        } else {
            attemptToFixTheIssue();
            return foo(recursionCounter + 1);
        }
    }
}
0 голосов
/ 19 апреля 2019

Один простой способ: вместо переменной-члена для recursioncount сделайте tryNumber с дополнительным аргументом для foo, по умолчанию = 1.(Технически перегруженная функция, поскольку Java не использует параметры по умолчанию)

0 голосов
/ 19 апреля 2019

Изначально метод foo() должен вызываться извне этого метода.Это ваш первый звонок, и именно там должен быть ваш try-catch.

Псевдокод.Не скомпилировано и не проверено.

public static void main(String[] args) {
    try {
        ReturnType rt = foo();
    }
    catch (Exception e) {
    }
}

ReturnType foo() throws Exception {
    ReturnType returnType = new ReturnType();
    if (recursion_counter == 5) {
        throw new Exception();
    }
    else {
        foo();
    }
}
...