The first thing is:
Don't have too complex functions doing too complicated things.
If you can't avoid complex functions, there are various other tools to handle the situation.
In C and other languages people often use goto
for the reason.
void func() {
/* .. code .. */
if (condition()) goto end;
/* ... more code ...*/
end:
cleanup();
}
Now some people dislike goto
even in such cases, so they emulate goto
using a do { ... } while(0)
loop:
void func() {
do {
/* .. code .. */
if (condition()) break;
/* ... more code ...*/
} while(0);
cleanup();
}
Some languages, for instance PHP, allow giving a parameter to the break
-keyword to jump multiple levels out:
function func() {
do {
/* .. code .. */
if(something() {
/* some code */
if (condition()) break 2;
/* ... */
}
/* ... more code ...*/
} while(0);
cleanup();
}
But there are languages with higher-level constructs. C++ for instance has destructors, there people use the RAII pattern:
struct cleanup {
~cleanup() {
/* .. do cleanup ... */
}
}
void func() {
cleanup cleaner; // this stack object will be destroyed on
// scope exit by calling the destructor
if (condition()) return;
/* ... more code ...*/
}
Some other languages have neither goto
, nor nested break, nor destructors. Thus Java programmers have to live with nested if's, abuse exceptions, ... or make the code simpler.
public static void func() {
try {
/* .. code .. */
if(something() {
/* some code */
if (condition()) throw new ControlFlowException();
/* ... */
}
/* ... more code ...*/
} catch (ControlFlowException e) {
/* ignore */
} finally {
cleanup();
}
}
So yes, alternative concepts exist and differ by language.
goto
for that.