0

I seem to be stuck with a very simple task that would require GOTO statements and, in my opinion, would justify a use of those.

I have the very simple task to exit a void on different conditions. Within its code, several dozen operations are being done and most of them can fail. I test them with try {}.

Now, based on the criticality of the operation, I either need to exit immediately and do nothing else, or, I just need to interrupt control flow and jump to a final point to do some cleaning up and then exit the method.

MWE:

public void myMethod () {
    try { op1(); } catch (Exception e) { return; } // Fail here: exit immediately
    try { op2(); } catch (Exception e) { cleanUpFirst(); return; } // Fail here: do Cleaning up first, then exit
    try { op3(); } catch (Exception e) { return; } // Fail here: exit immediately
    try { op4(); } catch (Exception e) { cleanUpFirst(); return; } // Fail here: do Cleaning up first, then exit
    try { op5(); } catch (Exception e) { cleanUpFirst(); return; } // Fail here: do Cleaning up first, then exit
    // ....
}
public void cleanUpFirst() { /* do something to clean up */ }

For code readability, I'd like to a) avoid a separate function and b) do not have more than one statement within the catch block; it just blows up the code. So, in my opinion this would perfectly justify the use of a GOTO statement.

However, the only solution I came up with, given that only two outcomes are possible, is this:

public void myMethod () {
    do {
        try { op1(); } catch (Exception e) { return; }
        try { op2(); } catch (Exception e) { break; }
        try { op3(); } catch (Exception e) { return; }
        try { op4(); } catch (Exception e) { break; }
        try { op5(); } catch (Exception e) { break; }
        // ....
    } while (1==0);
    /* do domething to clean up */
}

Yes, I have heard of exceptions and that is is the Java way. Is that not as overkilled as using the separate void? I do not need the specifics, I simply need a yes/no result from each operation. Is there a better way?

allprog
  • 15,913
  • 8
  • 54
  • 94
user1931751
  • 474
  • 3
  • 13
  • If you formatted this with an IDE, it'd look quite a bit different. It's also [bad practice to use exceptions for flow control](http://stackoverflow.com/questions/729379/why-not-use-exceptions-as-regular-flow-of-control). For many reasons, the first one I can think of is the time it'll take to build the exception stack. Could each op method return a boolean and use that to check? – david99world Jan 14 '14 at 08:41
  • @david99world I think that is a religious debate ;-) – Scary Wombat Jan 14 '14 at 08:43
  • No. Exceptions are part of abnormal program flow, and can do amazing and wonderful things to the C call stack (which most JVM's use). Secondly it is also considered bad practice to use blanket catch blocks (that catch the basic Exception [or worse, Throwable]). – Mikkel Løkke Jan 14 '14 at 08:50
  • 2
    Not really, the time it'd take to check a boolean is much smaller than creating a stack trace for an _exceptional_ case. It's an anti-pattern that has quite a lot of [documentation](http://c2.com/cgi/wiki?DontUseExceptionsForFlowControl) rather than something like checked vs unchecked, which is quite a classic religious argument. – david99world Jan 14 '14 at 08:51
  • Thanks so far, `opN();` is not always encapsulated in a separate method. It may as well be an Android command such as `Thread.sleep(100);`. So returning a `boolean` is not an option. And in regards to bad practice: Eclipse requires me to enclose certain IO operations with `try{}`; I simply do not need to handle the error, just ignore it and leave. Or the other case, clean up (as in reset some states and notify user) and leave afterwards. – user1931751 Jan 14 '14 at 15:38

3 Answers3

2

why not

boolean cleanupfirst = false;

            try {
                op1 ();
                cleanupfirst = true;
                op2 ();
                cleanupfirst = false;
                op3 ();
            } catch (Exception e) {
                if (cleanupfirst)
                    cleanup ();
                return;
            }
Scary Wombat
  • 41,782
  • 5
  • 32
  • 62
  • That would certainly be a viable alternative. Are there advantages / disadvantages with several statements within a `try`-block? Is that not as "bad" as my initial approach? – user1931751 Jan 14 '14 at 15:43
1

You're over-thinking it.

4 minor adjustments.

  1. Let Opn() return a boolean for success or failure, rather than throwing an Excpetion.
  2. Let CleanupFirst handle program termination (you can rename it to clean exit if you want). The new parameter passed to CleanExit is the System.exit code.
  3. Use System.Exit to return a proper return code to the OS, so you can use it in scripting.
  4. It does not seem like your program has a successful path.

    if (!op1())
        System.exit(1); // <- send a failed returncode to the OS.
    
    if(!op2())
        cleanExit(2);
    
    if (!op3())
        System.exit(3); // <- send a failed returncode to the OS.
    
    if (!op4())
        cleanExit(4);
    
    if (!op5())
        cleanExit(5);
    
    cleanExit(0);
    
Mikkel Løkke
  • 3,439
  • 20
  • 34
0

More methods for better readability:

public void myMethod() {
    try {
        tryOp1();
        tryOp2();
        ...
    } catch(Exception ignore) {}
}

public void tryOp1() throws Exception {
    op1();
}

public void tryOp2() throws Exception {
    try {
        op1();
    } catch (Exception e) {
        cleanUp();
        throw e;
    }
}
Seelenvirtuose
  • 19,157
  • 6
  • 34
  • 57