Unreachable Catch Block - A Most Unobvious Bug
Join the DZone community and get the full member experience.
Join For FreeEarlier today I was working on some HTTP comms code adding a few
changes, which are of no consequence here. One of the things that the
code did was to read data from a server and, if the read failed, then it
re-newed the connection and retried the read. The code ran something
like this:
HttpClient httpclient = // this is org.apache.http.client.HttpClient HttpResponse response; try { response = httpclient.execute(httpget, localContext); } catch (HttpResponseException e) { refreshHttpClient(httpclient); response = httpclient.execute(httpget, localContext); }
The idea is that the execute() method is supposed to throw an HttpResponseException in order to trigger a re-connection, except that the execute() method, according to the JavaDoc will NEVER throw that exception. You’d therefore expect that the compiler to give you an “Unreachable catch block” error, EXCEPT THAT IN THIS CASE IT DOESN’T. Why?
The answer is that the execute() method throws an IOException; an exception that is a superclass of the catch block exception HttpResponseException. The catch block will ignore the superclass exception as it’s only looking for the subclass exception.
To prove it, take a look at the simple example below.
public class CatchingExceptionsExample { public static class SampleClass { /** * Example method - throws IOException * * @throws IOException */ public void method() throws IOException { throw new IOException("Whoops"); } } public static class MyException extends IOException { private static final long serialVersionUID = 1L; public MyException(String msg) { super(msg); } } public static void main(String[] args) throws IOException { System.out.println("Running"); try { SampleClass sample = new SampleClass(); sample.method(); } catch (MyException e) { System.out.println("Exception Caught"); } finally { System.out.println("Ending"); } } }
Here I have an exception MyException that extends IOException and a class SampleClass that implements a sample method: method(), which throws an IOException.
The output from this code is:
Running Ending
...demonstrating that the catch block is unreachable.
Now, my first thought was to categorise this as a bug in Java, after all you want to know when there's an unreachable catch block and the compiler / eclipse usually tells you about it with this message...
...but it isn't a bug in Java it's there intentionally and it's just one of those little Gotchas that leaps up and bites you. The reason it it intentional can be explained by looking at the following chunk of code...
public class CatchingExceptionsExample2 { public static class SampleClass { public void method() throws IOException { AnotherSampleClass anotherSampleClass = new AnotherSampleClass(); anotherSampleClass.anotherMethod(); } } public static class AnotherSampleClass { public void anotherMethod() throws MyException { throw new MyException("My Exception"); } } public static class MyException extends IOException { private static final long serialVersionUID = 1L; public MyException(String msg) { super(msg); } } public static void main(String[] args) throws IOException { System.out.println("Running"); try { SampleClass sample = new SampleClass(); sample.method(); } catch (MyException e) { System.out.println("Exception Caught"); } finally { System.out.println("Ending"); } } }
In this code the method() method creates AnotherSampleClass and calls anotherMethod(). anotherMethod() does throw MyException, which because it's a subclass of IOException gets passed up the call-stack without any problems and is caught in the main() method. This time the output is:
Running Exception Caught Ending
Finally, I guess the point is that the compiler can't raise this gotcha as a problem as it'll never know if a method called in a try/catch block that then calls another method in an class or another class will throw an exception that is a subclass of the originally thrown exception... phew.
From http://www.captaindebug.com/2012/02/unreachable-catch-block-most-unobvious.html
Blocks
Opinions expressed by DZone contributors are their own.
Comments