Exception handling code must guarantee its fail-safe mechanism, and one of the important rules is as follows:
The try-catch-finally
last exception that is thrown in the block is passed in the call stack.
All early exceptions will disappear.
If catch
finally
an exception is thrown from one or block, then this exception may cause the exception that is try
caught in the block to be hidden. This can be misleading when you are trying to determine the cause of the exception.
The following is a non-fail-safe
classic example of exception handling:
null;try { new"myFile.txt" ); /* do something with the stream */}catch ( IOException e ) { thrownewWrapperException( e );}finally { try { input.close(); } catch ( IOException e ) { thrownewWrapperException( e ); }}
If FileInputStream
the constructor throws an FileNotFoundException
exception, what do you think will happen?
The block is executed first catch
, and the block will only re-throw the exception that is wrapped in WrapperException
.
Next, the finally
block is executed to close the input stream. However, because the FileInputStream
constructor throws an FileNotFoundException
exception, the reference variable "input" will be the null
. The result will be an finally
exception thrown from the block NullPointerException
. NullPointerException
is not catch ( IOException e )
caught by the clause, so it will be passed in the call stack. And the first catch block is thrown WrapperException
away.
The correct way to handle this situation is to check whether the reference allocated in the block is the first before calling any methods try
null
. For example, like this:
inputstream input = null ; try {input = new fileinputstream ( "myFile.txt" ); //do something with the stream } catch (IOException e) {//first catch block throw new wrapperexception (e);} finally {try {if (input! = null ) Input.close (); } catch (IOException e) {//second catch block throw new wrapperexception (e); }}
But even if this is still a problem, let's assume that the "myFile.txt" file exists, so the "input" reference now points to a valid one FileInputStream
. We also assume that an exception is thrown when the input stream is processed, when the first catch clause is caught and thrown, and the WrapperException
WrapperException
clause is executed before it is passed to the call stack finally
. If the input.close()
call fails, it is thrown and IOException
caught and thrown by the second catch clause WrapperException
, which disappears again from the first catch clause WrapperException
, and only the second catch is WrapperException
passed to the call stack.
As you can see, failsafe (fail safe) exception handling is not always worthless. The InputStream
processing examples are not even the most complex examples you can encounter. There is more likelihood of errors in the transactions in JDBC. An exception may occur when you try to commit, then roll back, and finally try to close the connection. All of these possible exceptions should be handled by exception handling code, so none of them will cause the first thrown exception to disappear. One way to do this is to make sure that the last exception that is thrown contains all the exceptions that were previously thrown, so that the developer can understand the cause of the error.
The features in Btw,java 7 try-with-resources
make it easier to implement fail-safe exception handling.
Original link: http://tutorials.jenkov.com/java-exception-handling/fail-safe-exception-handling.html
Java fail-safe exception handling