Friday, 26 December 2014

Suppressed exceptions in java 7

Background

In Java 7 new feature was introduced - try-with-resources statement where resources will be autoclosed. We will come to that. But this feature introduced another important topic and that is suppressed Exceptions and that is what we will discuss in this post.


Suppressed Exception in Java 6

Consider simple try-catch block

public class HelloWorld {

    public static void main(String args[]) {
        try {
            test();
        } catch (Exception ex) {
            System.out.println(ex);
        }
    }

    public static void test() throws Exception {
        try {
            System.out.println("In try block");
            throw new NullPointerException("NPE from try block");
        } finally {
            System.out.println("In finally block");
            throw new NullPointerException("NPE from finally block");
        }
    }

}

and the output is : 

In try block
In finally block
java.lang.NullPointerException: NPE from finally block

Where did the NPE thrown from try block go ? Well it was lost or ignored. One dirty way to retain the cause Exception is to chain it. 

To summarize what above part says is that exception thrown from finally block eats up the exception that might have been thrown from try block.

Now lets head over to Java 7 try-with-resource statement to see what it has for us.

Try With Resources statement in Java7

Hope you are aware what try-with-resource statements are. If not please first go through try-with-resource section of Whats new in Java7 post.

As you know resource that can be used in try-with-resource statement needs to implement Closable or AutoClosable interface. Lets define one such resource.

public class DefectiveResource implements AutoCloseable {

    public DefectiveResource() {
        System.out.println("This is defective constructor");
        throw new NullPointerException("From DefectiveResource constructor");
    }

    public DefectiveResource(String str) {
        System.out.println("This is non - defective constructor.");
    }

    public void process() {
        throw new NullPointerException("From DefectiveResource process");
    }

    @Override
    public void close() throws Exception {
        throw new NullPointerException("From DefectiveResource close");
    }

}


Ok we have our resource. Lets go ahead and test it out.


Case 1 : Exception thrown while instantiating a resource

Consider following code - 

public class HelloWorld {

    public static void main(String args[]) {

        try {
            testSuppressException();
        } catch (Exception ex) {
            System.out.println(ex);
        }

    }

    public static void testSuppressException() throws Exception {
        try (DefectiveResource dr = new DefectiveResource()) {
            System.out.println("In testSuppressException");
        }

    }
}


Output would print -

This is defective constructor
java.lang.NullPointerException: From DefectiveResource constructor

meaning try block was not executed. That's right if exception is thrown while creating resources in try-with-resource block try block is not even executed. Don't even bother thinking about closing resource as it was not created in the first place.

Case 2: Exception is thrown from try-with-resource block as well as try block

 This case is a little tricky. When I say Exception is thrown from try-with-resource block it mean exception is thrown during closing of resources. If exception occurs while instantiating resource it will fall under case1. So Exception is thrown while closing resource (which occurs as a part of try-with-resource statement)  and exception is also thrown from try block.

public class HelloWorld {

    public static void main(String args[]) {

        try {
            testSuppressException();
        } catch (Exception ex) {
            System.out.println(ex);
        }

    }

    public static void testSuppressException() throws Exception {
        try (DefectiveResource dr = new DefectiveResource("Test")) {
            System.out.println("In testSuppressException");
            dr.process();
        }

    }

}

And the output is : 

This is non - defective constructor.
In testSuppressException
java.lang.NullPointerException: From DefectiveResource process

Now lets analyze the code. You can see "In testSuppressException" in the output that means instantiating went through. process() method must have thrown Exception and close() method would have too. But we see only Exception thrown by process() method.

That's right Exception thrown while closing resource from try-with-resource statement was suppressed by the Exception from try block. You can get the suppressed Exception as follows - 

public class HelloWorld {

    public static void main(String args[]) {

        try {
            testSuppressException();
        } catch (Exception ex) {
            System.out.println(ex);
            final Throwable[] suppressedException = ex.getSuppressed();
            if(suppressedException.length > 0)
                System.out.println("Suppresed Exception : " + suppressedException[0]);
        }

    }

    public static void testSuppressException() throws Exception {
        try (DefectiveResource dr = new DefectiveResource("Test")) {
            System.out.println("In testSuppressException");
            dr.process();
        }

    }

}


and output is - 

This is non - defective constructor.
In testSuppressException
java.lang.NullPointerException: From DefectiveResource process
Suppresed Exception : java.lang.NullPointerException: From DefectiveResource close

Hope it's clear now that Exception from try block suppressed Exception that occurred from closing resource in try-with-resource statement. 

I will go 2 step ahead and tell you this. Try-with-resource create an implicit finally statement and tries to close resources in it. and this exception is suppressed by exception from try block.

Note: A try-with-resources statement can have catch and finally blocks just like an ordinary try statement. In a try-with-resources statement, any catch or finally block is run after the resources declared have been closed. 

That means if you provide an explicit finally statement that's ok but resources will be closed before this executed. Meaning the implicit finally block I was talking about will be completed before this.

And this brings me to 3rd case.

Case 3 : Exception thrown from explicit finally block with try-with-res statement

So if Exception is thrown from try-with-resource block (during close), it is also thrown from try block and then again from finally block - 


public class HelloWorld {

    public static void main(String args[]) {

        try {
            testSuppressException();
        } catch (Exception ex) {
            System.out.println(ex);
            final Throwable[] suppressedException = ex.getSuppressed();
            if(suppressedException.length > 0)
                System.out.println("Suppresed Exception : " + suppressedException[0]);
        }

    }

    public static void testSuppressException() throws Exception {
        try (DefectiveResource dr = new DefectiveResource("Test")) {
            System.out.println("In testSuppressException");
            dr.process();
        }finally {
            throw new NullPointerException("From explicit finally block");
        }

    }

}

and the output here is - 

This is non - defective constructor.
In testSuppressException
java.lang.NullPointerException: From explicit finally block

Lets go step by step. Resource instantiation went through. Exception is thrown from try block and then while closing (from implicit finally block if you are imagining that way). So far as per above case exception from try block takes precedence and suppressed exception occurring from close() in try-with-resource statement. But when explicit finally block is executed it again ignores all these exceptions and throws it's own (similar to Java 6 example at the top).

Also if exception was thrown while creating/instantiating resources as in case 1 then try block will not be executed and again exception from explicit finally block would override this.

Bottom line : If your explicit finally block throws Exception all your previous exceptions are eaten up.

Important point of this post was to explain that the Exception from close() is suppressed by Exception from try block.

Note : The close methods of resources are called in the opposite order of their creation.

Related Links




No comments:

Post a Comment

t> UA-39527780-1 back to top