Java 7 Exception handling by R4R Team

Java 7 Exception handling

Handling more than one type of exception

In Java SE 7 and later, a single catch block can handle more than one type of exception. Consider the following example, which contains duplicate code in each of the catch blocks:

//Prior to Java 7

catch (IOException ex) {

     logger.log(ex);

     throw ex;

catch (SQLException ex) {

     logger.log(ex);

     throw ex;

}

In releases prior to Java SE 7, it is difficult to create a common method to eliminate the duplicated code because the variable ex has different types.

The following example, which is valid in Java SE 7 and later, eliminates the duplicated code:

catch (IOException|SQLException ex) { // java 7 handling more than one type of exception

    logger.log(ex);

    throw ex;

}

The catch clause specifies the types of exceptions that the block can handle, and each exception type is separated with a vertical bar (|). Some other advantages apart from syntactical improvement:

  • Bytecode generated by compiling a catch block that handles multiple exception types will be smaller (and thus superior) than compiling many catch blocks that handle only one exception type each. 

  • A catch block that handles multiple exception types creates no duplication in the bytecode generated by the compiler; the bytecode has no replication of exception handlers. 

Note: If a catch block handles more than one exception type, then the catch parameter is implicitly final. In this example, the catch parameter ex is final and therefore you cannot assign any values to it within the catch block.

Re-throwing exceptions with more inclusive type checking

The Java SE 7 compiler performs more precise analysis of rethrown exceptions than earlier releases of Java SE. This enables you to specify more specific exception types in the throws clause of a method declaration.

Consider the following example:

  static class FirstException extends Exception { }

  static class SecondException extends Exception { }

  public void rethrowException(String exceptionName) throws Exception {

    try {

      if (exceptionName.equals("First")) {

        throw new FirstException();

      } else {

        throw new SecondException();

      }

    } catch (Exception e) {

      throw e;

    }

  }

This examples's try block could throw either FirstException or SecondException. Suppose you want to specify these exception types in the throws clause of the rethrowException method declaration. In releases prior to Java SE 7, you cannot do so. Because the exception parameter of the catch clause, e, is type Exception, and the catch block rethrows the exception parameter e, you can only specify the exception type Exception in the throws clause of the rethrowException method declaration.

However, in Java SE 7, you can specify the exception types FirstException and SecondException in the throws clause in the rethrowException method declaration. The Java SE 7 compiler can determine that the exception thrown by the statement throw e must have come from the try block, and the only exceptions thrown by the try block can be FirstException and SecondException. Even though the exception parameter of the catch clause, e, is type Exception, the compiler can determine that it is an instance of either FirstException or SecondException:

  public void rethrowException(String exceptionName) throws FirstException, SecondException {

    try {

      // ...

    }

    catch (Exception e) {

      throw e;

    }

  }

This analysis is disabled if the catch parameter is assigned to another value in the catch block. However, if the catch parameter is assigned to another value, you must specify the exception type Exception in the throws clause of the method declaration.

In detail, in Java SE 7 and later, when you declare one or more exception types in a catch clause, and rethrow the exception handled by this catch block, the compiler verifies that the type of the rethrown exception meets the following conditions:

  • The try block is able to throw it.

  • There are no other preceding catch blocks that can handle it.

  • It is a subtype or supertype of one of the catch clause's exception parameters.

The Java SE 7 compiler allows you to specify the exception types FirstException and SecondException in the throws clause in the rethrowException method declaration because you can rethrow an exception that is a supertype of any of the types declared in the throws.

In releases prior to Java SE 7, you cannot throw an exception that is a supertype of one of the catch clause's exception parameters. A compiler from a release prior to Java SE 7 generates the error, "unreported exception Exception; must be caught or declared to be thrown" at the statement throw e. The compiler checks if the type of the exception thrown is assignable to any of the types declared in the throws clause of the rethrowException method declaration. However, the type of the catch parameter e is Exception, which is a supertype, not a subtype, of FirstException andSecondException.

SuppressednException in java 7

Suppressed Exception as name suggest, are exceptions thrown in the code but were ignored somehow. If you remember try-catch-finally block execution sequence and how they return any value or exceptions, you will recall that exceptions thrown in finally block are suppressed is exception is thrown in try block also. Before java 7, you was informed about these exceptions by logging if implemented, but you didn’t have any control over these types of exceptions once finally block is over.

Well, with new features in java 7 you got control over these suppressed exceptions as well. How? Lets see !!

Sections in this post

What are suppressed exceptions?
Example usage
Demonstration in different scenarios

What are suppressed exceptions?

In java 7, perhaps the most common use case for encountering suppressed exceptions is when a try-with-resources statement (which is the one type of try that does not require a catch or finally clause according to Java Language Specification ) encounters an exception within the try block and then encounters another exception in implicitly trying to close the related resource. Because multiple exceptions may occur while closing AutoCloseable resources, additional exceptions are attached to a primary exception as suppressed exceptions.

A new constructor and two new methods were added to the Throable class (parent of Exception and Error classes) in JDK 7. These are as below:

Throwable.getSuppressed(); // Returns Throwable[]
Throwable.addSuppressed(aThrowable);

Example scenario

For example while writing to output stream, an exception can be thrown from the try block, and up to two exceptions can be thrown from the try-with-resources statement when it tries to close the stream. If an exception is thrown from the try block and one or more exceptions are thrown from the try-with-resources statement, then those exceptions thrown from the try-with-resources statement are suppressed, and the exception thrown by the block is the one that is thrown by the closeStream() method.

You can retrieve these suppressed exceptions by calling the Throwable.getSuppressed method from the exception thrown by the try block.

Demonstration in different scenarios

For example purpose, I am writing an auto closeable resource (i.e. DirtyResource.java) which throws exceptions whether we try to access it or close it. This way we will be able to see different behavior when accessed in different manner.


public class DirtyResource implements AutoCloseable

{

    /**

     * Need to call this method if you want to access this resource

     * @throws RuntimeException no matter how you call this method

     * */

    public void accessResource()

    {

        throw new RuntimeException("I wanted to access this resource. Bad luck. Its dirty resource !!!");

    }

 

    /**

     * The overridden closure method from AutoCloseable interface

     * @throws Exception which is thrown during closure of this dirty resource

     * */

    @Override

    public void close() throws Exception

    {

        throw new NullPointerException("Remember me. I am your worst nightmare !! I am Null pointer exception !!");

    }

}

Scenario 1: As it was prior to suppressed exceptions support


package r4r;

 

import static java.lang.System.err;

 

public class SuppressedExceptionDemoWithTryFinallyPrevious

{

    /**

    * Executable member function demonstrating suppressed exceptions

    * One exception is lost if not added in suppressed exceptions list

    */

    public static void memberFunction() throws Exception

    {

        DirtyResource resource= new DirtyResource();

        try

        {

              resource.accessResource();

        }

        finally

        {

            resource.close();

        }

    }

 

    public static void main(String[] arguments) throws Exception

   {

      try

      {

          memberFunction();

      }

      catch(Exception ex)

      {

          err.println("Exception encountered: " + ex.toString());

          final Throwable[] suppressedExceptions = ex.getSuppressed();

          final int numSuppressed = suppressedExceptions.length;

          if (numSuppressed > 0)

          {

              err.println("tThere are " + numSuppressed + " suppressed exceptions:");

              for (final Throwable exception : suppressedExceptions)

              {

                  err.println("tt" + exception.toString());

              }

          }

      }

   }

}

 

Output:

 

Exception encountered: java.lang.NullPointerException: Remember me. I am your worst nightmare !! I am Null pointer exception !!

As you can see that only one exception was captured and second RuntimeException was suppressed.

Scenario 2: As it is after the suppressed exceptions support in java 7





package r4r;

 

import static java.lang.System.err;

 

public class SuppressedExceptionDemoWithTryFinallyNew

{

    /**

    * Executable member function demonstrating suppressed exceptions

    * Suppressed expression is added back in primary exception

    */

    public static void memberFunction() throws Exception

    {

        Throwable th = null;

        DirtyResource resource= new DirtyResource();

        try

        {

              resource.accessResource();

        }

        catch(Exception e)

        {

            th = e;

        }

        finally

        {

            try

            {

                resource.close();

            }

            catch(Exception e)

            {

                if(th != null)

                {

                    e.addSuppressed(th); //Add to primary exception

                    throw e;

                }

            }

        }

    }

   /**

    * Executable function demonstrating suppressed exceptions.

    */

   public static void main(String[] arguments) throws Exception

   {

      try

      {

          memberFunction();

      }

      catch(Exception ex)

      {

          err.println("Exception encountered: " + ex.toString());

          final Throwable[] suppressedExceptions = ex.getSuppressed();

          final int numSuppressed = suppressedExceptions.length;

          if (numSuppressed > 0)

          {

              err.println("tThere are " + numSuppressed + " suppressed exceptions:");

              for (final Throwable exception : suppressedExceptions)

              {

                  err.println("tt" + exception.toString());

              }

          }

      }

   }

}

 

Output:

 

Exception encountered: java.lang.NullPointerException: Remember me. I am your worst nightmare !! I am Null pointer exception !!

    There are 1 suppressed exceptions:

        java.lang.RuntimeException: I wanted to access this resource. Bad luck. Its dirty resource !!!

Here, in catch block we are able to access both exception. One as primary exception and second as suppressed exception.

Scenario 3: Using with try-with-resource block in a member function and catching the exception


package r4r;

 

import static java.lang.System.err;

 

public class SuppressedExceptionDemoWithTryCatch

{

    public static void memberFunction() throws Exception

    {

        try (DirtyResource resource= new DirtyResource())

          {

              resource.accessResource();

          }

    }

   /**

    * Executable member function demonstrating suppressed exceptions using try-with-resources

    */

   public static void main(String[] arguments) throws Exception

   {

      try

      {

          memberFunction();

      }

      catch(Exception ex)

      {

          err.println("Exception encountered: " + ex.toString());

          final Throwable[] suppressedExceptions = ex.getSuppressed();

          final int numSuppressed = suppressedExceptions.length;

          if (numSuppressed > 0)

          {

              err.println("tThere are " + numSuppressed + " suppressed exceptions:");

              for (final Throwable exception : suppressedExceptions)

              {

                  err.println("tt" + exception.toString());

              }

          }

      }

   }

}

Output:

Exception encountered: java.lang.RuntimeException: I wanted to access this resource. Bad luck. Its dirty resource !!!

    There are 1 suppressed exceptions:

        java.lang.NullPointerException: Remember me. I am your worst nightmare !! I am Null pointer exception !!

Great !! We are able to see both exceptions when using try-with-resource in member function.

Scenario 4: Using with default try-with-resource block



package r4r;

 

public class SuppressedExceptionDemoWithTryWithResource

{

   /**

    * Demonstrating suppressed exceptions using try-with-resources

    */

   public static void main(String[] arguments) throws Exception

   {

      try (DirtyResource resource= new DirtyResource())

      {

          resource.accessResource();

      }

   }

}

 

Output:

 

Exception in thread "main" java.lang.RuntimeException: I wanted to access this resource. Bad luck. Its dirty resource !!!

    at DirtyResource.accessResource(DirtyResource.java:9)

    at SuppressedExceptionDemoWithTryWithResource.main(SuppressedExceptionDemoWithTryWithResource.java:12)

    Suppressed: java.lang.NullPointerException: Remember me. I am your worst nightmare !! I am Null pointer exception !!

        at DirtyResource.close(DirtyResource.java:19)

        at SuppressedExceptionDemoWithTryWithResource.main(SuppressedExceptionDemoWithTryWithResource.java:13)




Leave a Comment: