views:

901

answers:

12

Given that multiple return statements are acceptable (I disagree, but let us digress), I'm looking for a more acceptable way to achieve the following behavior:

Option A: multiple returns, repeated code block

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

It makes me feel dirty to see the same (little) code block repeated three times each time the method returns. Furthermore, I would like to clarify that the two return false statements above can certainly be described as returning mid-method... they are absolutely not "guard statements."

Is Option B slightly more acceptable? I feel that I may abusing try/finally, and I'm hoping there is something completely different that I should be doing.

Option B: multiple returns, try/finally block (without catch blocks / exceptions)

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 ... */
    }
}

Finally, Option C is the best solution in my book, but my team doesn't like this approach for whatever reason(s), hence I'm looking for a compromise.

Option C: single return, conditional blocks

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

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

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

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

If you want to discuss multiple return statements, please do so in this question.

+27  A: 

If the code needs to run even when any other code throws an exception, then the finally block is the correct solution.

If it need not run in the case of an exception (i.e. it's only necessary for "normal" returns), then using finally would be abusing the feature.

Personally I'd rewrite that method in the single-return-point style. Not because I religiously subscribe to that idea (I don't), but because it is best suited for these kind of end-of-method codes.

When that code turns out to be overly complicated (and that's a very real possibility), then it's time to refactor the method by extracting one or more methods.

The simplest refactoring would be something like this:

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;
}
Joachim Sauer
Then what *should* I be doing? There are no exception to catch here.
Dolph
+25  A: 

Exceptions should be exceptional so I don't like option B if there are no other exceptions around

If code is always needed how about refactoring into 2 functions

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;
}
Mark
+1 for correctly answering the second half of the question. But the comment that finally is incorrect in the absence of exceptions is just plain wrong. try/finally exists in order to execute some block of code and then always do something else regardless of how that block exits - finally is often tied to exception handling but not limited to that; it is perfectly legitimate to use finally for exit handling too.
Software Monkey
Accepting this answer since this code was posted five minutes before Joachim Sauer's. This is the *duh* solution I was hoping for.
Dolph
But I did not say it is incorrect. I said I did not like it - it is like the original question a matter of style
Mark
I agree with @SoftwareMonkey; a `finally` block is independent of any `catch` block. In fact, there are way too many instances of `try-catch` in Java code that really should be `try-finally`. In other words, exceptions are often caught and mis-handled, when what is needed is to clean up a resource and let the exception be handled by a caller with more context.
erickson
@Mark: Sorry read in an inference that you may not have intended (but hey, I still +1'd you!)
Software Monkey
I keep hearing the catchy phrase "Exceptions should be exceptional" but never an explanation of what this *means*. Rare in code? This is probably the only place he does this. Rare in execution? I get a lot of IOExceptions, so would you say I should make IO conditions not use Exceptions? Or do you mean "exceptional" in the more general "unusual and impressive", in which case this use looks fine? In general, what do you mean by "exceptional"?
Ken
I suppose nearest is "unusual and impressive". Iy can also depend on the language, e.g. Python will use exceptions more than C++ or Java. If the bad condition is normal in the execution path than don't use an exception
Mark
A: 

Using try/finally for controlling flow feels to me like using GOTO.

cherouvim
And what is wrong with judicious use of goto when it makes the program flow clearer and less error-prone? After all, that is what break, continue and return are, esp labelled break and continue.
Software Monkey
I think breaks are okay, continues are okay, and returns are okay, but if you use them all in the same method... YIKES!
Dolph
@Dolph: If you haven't used all of them in the same method, you probably haven't been writing code for very long. (smile). Get back to me in 10 or 20 years.
Software Monkey
I think GOTO can be very useful at times, but like most things in life they are only good in moderation. Use the tool at the right time and you shall be rewarded, but if you use it all the time you might find yourself in a bad place.
Brian T Hannan
@Software Monkey: If I ever see all three in one method *in Java*, heads will roll.
Dolph
@Dolph: It's very good to have principles and to follow them... just remember that programming is best approached as an art, not a religion (and despite us calling ourselves engineers, it's not strictly an engineering discipline).
Software Monkey
using return, break and continue in one method is blasphemy nevertheless ;)
sfussenegger
A: 

Is there a reason that you can't simply store the return value, and fall out of the 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;
chris
Because this is horrible code that keeps getting more horrible the more conditions that exist.
Software Monkey
Some times you have to break the rules. If it solves your problem, then do it. Architectural purity and abstract concepts sometimes gets in the way of reality.
chris
@Chris: Absolutely. But using try/finally is far better code than this.
Software Monkey
That's what I meant: it doesn't matter if it's an "abuse" of try/finally, if it works and solves your problems, do it.
chris
A: 

IMO the idea is to put a try block over a small part of code (e.g. a method call) that can throw a known exception (e.g. reading from a file, reading an int to a String). So putting a try block over the whole code of a method is really not the way to go, unless you are actually expecting each and every if condition code to potentially throw the same set of exceptions. I don't see a point in using a try block just for the sake of using a finally.

If I am not mistaken, putting large chunks of code inside a try also makes it a lot slower, but not sure if this is true in the latest versions of Java.

Personally, I would go with Option C. But I don't have anything against Option A either.

MAK
I didn't consider a performance impact, I would like to know if there is one.
Dolph
Exception *generation* is *relatively* expensive, I don't think exception *handling* or try/finally itself is particularly so.
Software Monkey
@Dolph Matthews: I am really not sure about this, and Software Monkey is probably right. I guess the best thing to do to know for sure is to profile your code with the large try block and find out yourself.
MAK
+13  A: 

This is a perfect place for a GOTO

*ducks*

David Oneill
Hey, it was worth the laugh :P
Dolph
I assume, and hope, David is serious.
Software Monkey
In C or C++, using `goto` would be acceptable, since you're trying to exit early from the method.
Loadmaster
@Loadmaster:In C++ one would typically use something like a `ScopeGuard` to execute that final block of code.
Jerry Coffin
A: 

Unless the code that must run at the end of the method uses method local variables, you could extract it into a method like:

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

this still doesn't look very nice, but it is better than using goto-like constructs. To convince your team mates that a 1-return solution might not be that bad, you can also present a version using 2 do { ... } while (false); and break's (*evil grin*.)

rsp
+1  A: 

How about breaking it up a little more to give something more ( excusing my not having used Java's logical operators in quite some time ) like this:

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; 
}
glenatron
+1 but I think bitwise operators would make `myMethod()` a little more clear. `bool returnval = true;` `returnval ` etc
Dolph
@Dolph Mathews it would look cleaner, but each method will be executed, regardless of returnval!
sfussenegger
glenatron
@glenatron thanks for helping with the technical term ;) I still have the felling it's a little Perl'ish tough: `$val = foo() unless !$val;` - at least as far as I remember - thank god I've forgotten most of it :)
sfussenegger
There is no such thing as perlish. Perl encompasses pretty much every possible way of doing something. That is why it is so irritatingly difficult to read Perl written by anyone else :)
glenatron
+2  A: 

If the code needs to run even when there is an Exception, then finally is not just a good choice, it is a must. If that is not the case, finally is not necessary. Looks like you want to find format that "looks" best. But there is little more at stake here.

fastcodejava
+2  A: 

Don't abuse try/finally unless you need to break out of inner loops. Abuse do/while.

bool result = false;
do {
  // Code
  if (condition1) break;
  // Code
  if (condition2) break;
  // . . .
  result = lastCondition
} while (false);
Rex Kerr
you cannot be serious! Anybody will instantly know what `finally` is used for. The intention of `do { ... } while (false);` is by far less obvious.
sfussenegger
But anybody will not know instantly what the `try` is for--you think "dangerous exception-throwing code ahead", not "some regular control-flow construct", and you might want real exceptions to fall through without executing finally (i.e. they're real uncaught exceptions). Since both constructs are weird, my real suggestion would be to refactor into two methods, but sometimes there's a lot of internal state to maintain and if your coding team refuses if-chains, having options like this can be helpful.
Rex Kerr
If you can't instantly understand what the finally block is doing, the code is flawed anyway: Either a) the try block is too long (having to scroll from the beginning of a try block to its end is a no-no - extract some methods!) or b) the catch block is too long (it shouldn't be doing more than some basic cleanup that should be quick to grasp too). As I haven't ever seen this abuse of do/while anywhere before, it took me two seconds to get it's intention - a good indicator that it isn't a very good choice.
sfussenegger
It's a bad choice unless used widely throughout that codebase; then at least those programmers would know what's going on. Given all the blocks of code in the example, it looked very likely to me that the try block *was* too long.
Rex Kerr
+2  A: 

Your option C solution is not far from optimal, since it adequately codes the proper execution sequence you're trying to accomplish.

Similarly, using nested if-statements do the same thing. It may be visually less appealing, but it's simpler to understand, and makes the execution flow pretty obvious:

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

Simplifying the code yields:

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

The simplified code also reveals what you're actually trying to achieve: you are using the test conditions to avoid executing code, therefore you should probably be executing that code when the conditions are false instead of doing something when they are true.

To answer your question about try-finally blocks: Yes, you can abuse them. Your example is not sufficiently complex enough to warrant the use of try-finally. If it were more complex, though, it might.

See my take on it at: Go To Statement Considered Harmful: A Retrospective, "Exception Handling".

Loadmaster
A: 

Can someone please explain to me why a the use of a Switch-Case wouldn't be optimal here?

nlast
Because thisCondition and thatCondition might both be true so both are executed. or thatCondition is changed in the thisCondition code
Mark