THE Java™ Programming Language, Fourth Edition

(Jeff_L) #1

If pre succeeds then we enter the try block and no matter what occurs we are guaranteed that post gets
executed. Conversely, if pre itself fails for some reason and throws an exception, then post does not get
executedit is important that pre occur outside the try block in this situation because post must not execute
if pre fails.


You saw the second form of the idiom in the stream searching example. In that case pre returns a value that
can be used to determine whether or not it completed successfully. Only if pre completed successfully is
post invoked in the finally clause:


Object val = null;
try {
val = pre();
// other actions
} finally {
if (val != null)
post();
}


In this case, we could still invoke pre outside the try block, and then we would not need the if statement
in the finally clause. The advantage of placing pre inside the try block comes when we want to catch
both the exceptions that may be thrown by pre and those that may be thrown by the other actionswith pre
inside the TRy block we can have one set of catch blocks, but if pre were outside the TRy block we would
need to use an outer TRy-catch block to catch the exceptions from pre. Having nested TRy blocks can be
further complicated if both pre and the other actions can throw the same exceptionsquite common with I/O
operationsand we wish to propagate the exception after using it in some way; an exception thrown by the
other actions would get caught twice and we would have to code our catch blocks to watch for and deal with
that situation.


A finally clause can also be used to clean up for break, continue, and return, which is one reason
you will sometimes see a try clause with no catch clauses. When any control transfer statement is
executed, all relevant finally clauses are executed. There is no way to leave a try block without
executing its finally clause.


The preceding example relies on finally in this way to clean up even with a normal return. One of the
most common reasons goto is used in other languages is to ensure that certain things are cleaned up when a
block of code is complete, whether or not it was successful. In our example, the finally clause ensures that
the file is closed when either the return statement is executed or the stream throws an exception.


A finally clause is always entered with a reason. That reason may be that the try code finished normally,
that it executed a control flow statement such as return, or that an exception was thrown in code executed
in the TRy block. The reason is remembered when the finally clause exits by falling out the bottom.
However, if the finally block creates its own reason to leave by executing a control flow statement (such
as break or return) or by throwing an exception, that reason supersedes the original one, and the original
reason is forgotten. For example, consider the following code:


try {
// ... do something ...
return 1;
} finally {
return 2;
}

Free download pdf