Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swallowing exception thrown in catch/finally block

Tags:

java

c#

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?

like image 918
maxyfc Avatar asked Oct 31 '09 14:10

maxyfc


4 Answers

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).

like image 200
duffymo Avatar answered Oct 05 '22 22:10

duffymo


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;
}
like image 28
CMerat Avatar answered Oct 05 '22 23:10

CMerat


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).

like image 25
fvu Avatar answered Oct 06 '22 00:10

fvu


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.

like image 44
homeInAStar Avatar answered Oct 05 '22 23:10

homeInAStar