Sprag
Sprag

Reputation: 69

Recursion within a try-catch-finally block: How to only call the finally block one time, on the original function call?

Let's say I have a function named foo(). Within foo() there is a try-catch-finally block. Inside the catch block, foo() is called recursively.

My question is:

How can I have the finally block only execute once, on the original function call?

I want to limit the number of recursive calls that can be made by simply using a counter (an Integer that I increment). Please see the example code below and you will have a generic understanding of what I am trying to accomplish:

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;
}

Unless I am mistaken, the finally block can potentially be called multiple times, which I do not want to happen.

If you believe there is a better way to accomplish this (e.g., using something other than an incrementing integer, etc.), then please share your thoughts.

Upvotes: 0

Views: 1856

Answers (3)

Holger
Holger

Reputation: 298203

Simply don’t use recursion for such a task:

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();
            }
        }
    }
}

Just for completeness, if you’re going to solve a task via recursion, don’t use instance fields to hold the local state of the recursion. When you keep local what is supposed to be local, there is no persistent state that needs a reset. (And, by the way, don’t use Integer objects where int values are sufficient)

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);
        }
    }
}

Upvotes: 2

Patrick Parker
Patrick Parker

Reputation: 4959

One simple way: instead of a member variable for recursioncount, make attemptNumber an extra argument to foo, with default=1. (Overloaded function technically, since Java doesn't do default parameters)

I think carrying this information along with the function call makes a bit more sense than keeping it as instance state-- which is not thread-safe BTW

Upvotes: 0

Abra
Abra

Reputation: 20914

Initially, method foo() must be invoked from outside of that method. That's your initial call and that's where your try-catch should be.

Pseudo code. Uncompiled and untested.

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();
    }
}

Upvotes: 1

Related Questions