Usually I come across situations where I have to swallow an exception thrown by the clean up code in the catch
/finally
block to prevent the original exception being swallowed.
For example:
// Closing a file in Java
public void example1() throws IOException {
boolean exceptionThrown = false;
FileWriter out = new FileWriter(“test.txt”);
try {
out.write(“example”);
} catch (IOException ex) {
exceptionThrown = true;
throw ex;
} finally {
try {
out.close();
} catch (IOException ex) {
if (!exceptionThrown) throw ex;
// Else, swallow the exception thrown by the close() method
// to prevent the original being swallowed.
}
}
}
// Rolling back a transaction in .Net
public void example2() {
using (SqlConnection connection = new SqlConnection(this.connectionString)) {
SqlCommand command = connection.CreateCommand();
SqlTransaction transaction = command.BeginTransaction();
try {
// Execute some database statements.
transaction.Commit();
} catch {
try {
transaction.Rollback();
} catch {
// Swallow the exception thrown by the Rollback() method
// to prevent the original being swallowed.
}
throw;
}
}
}
Let's assumed that logging any of the exceptions is not an option in the scope of method block, but will be done by the code calling the example1()
and example2()
methods.
Is swallowing the exceptions thrown by close()
and Rollback()
methods a good idea? If not, what is a better way of handling the above situations so that the exceptions are not swallowed?
I'm not a fan of catching and rethrowing an exception.
If you catch it, do something with it - even if it's just logging the exception.
If you can't do anything with it, don't catch it - add a throws clause to the method signature.
Catching an exception tells me that either you can deal with an exceptional situation and have a recovery plan or "the buck stops here" because an exception cannot propagate in that form any farther (e.g., no stack traces back to the user).
You can create a custom Exception
type that can hold both exceptions. If you overload the ToString()
, you can log both exceptions.
try
{
transaction.Commit();
}
catch(Exception initialException)
{
try
{
transaction.Rollback();
}
catch(Exception rollbackException)
{
throw new RollbackException(initialException, rollbackException);
}
throw;
}
That's exactly why Commons IO has an IOUtils.closeQuietly method. In most cases what goes wrong during the closing of a file is not that interesting.
Database transactions that have to be rolled back are potentially more interesting, as in that case the function didn't do what it was supposed to do (put stuff in the DB).
There's no reason to rollback the transaction in the C# code. If you close the connection wihtout rolling back the transaction (or committing it) that is equivalent and more efficient...
public void example2() {
using (SqlConnection connection = new SqlConnection(this.connectionString))
using (SqlCommand command = connection.CreateCommand())
using (SqlTransaction transaction = command.BeginTransaction()) {
// Execute some database statements.
transaction.Commit();
}
}
and you are done.
The using statement will ensure (via finally) that the connection is closed regardless of any exceptions and let the raw exception bubble out (with the full/correct stack trace). If an exception occurs before the call to Commit, the transaction will never commit and will be automatically rolled back when the transaction/connection closes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With