Rethrowing Exceptions


Nothing prevents you from catching an exception and then throwing it (or another exception) from within the catch block. This is known as rethrowing an exception.

A common reason to rethrow an exception is to catch it as close to its source as possible, log it, and then propagate it again. This technique can make it easier to determine the source of a problem.

 public void setUrl(String urlString) throws MalformedURLException {    try {       this.url = new URL(urlString);    }    catch (MalformedURLException e) {       log(e);       throw e;    } } private void log(Exception e) { // logging code.  The second half of this lesson contains more       // info on logging. For now, this method is empty. } 

In the above changes to setUrl, code in the catch block passes the caught exception object to the log method, then rethrows it. A refinement of this technique is to create and throw a new exception of a more application-specific type. Doing so can encapsulate the specific implementation details that caused the exception.

Instead of throwing a MalformedURLException, you want to throw an instance of the application-specific exception type SessionException. Once you have created the exception class:

 package sis.studentinfo; public class SessionException extends Exception { } 

You can alter test code to reflect the new exception type:

 public void testSessionUrl() throws SessionException {    final String url = "http://course.langrsoft.com/cmsc300";    session.setUrl(url);    assertEquals(url, session.getUrl().toString()); } public void testInvalidSessionUrl() {    final String url = "httsp://course.langrsoft.com/cmsc300";    try {       session.setUrl(url);       fail("expected exception due to invalid protocol in URL");    }    catch (SessionException success) {    } } 

Finally, you can change the production code to throw the new exception instead.

 public void setUrl(String urlString) throws SessionException {    try {       this.url = new URL(urlString);    }    catch (MalformedURLException e) {       log(e);       throw new SessionException();    } } 

The downside is that you lose information with this solution: If an exception is thrown, what is the true reason? In a different circumstance, code in the TRy block might throw more than one kind of exception. Rethrowing the application-specific exception would hide the root cause.

As a solution, you could extract the message from the root exception and store it in the SessionException instance. You would still lose the original stack trace information, however.

In J2SE 1.4, Sun added the ability to the Throwable class to store a root cause. The Throwable class provides two additional constructor forms: one that takes a Throwable as a parameter and another that takes both a message string and a Throwable as a parameter. Sun also added these constructors to the Exception and RuntimeException derivatives of Throwable. You may also set the root cause in the Throwable object after its construction via the method initCause. Later, you can retrieve the Throwable object from the exception by sending it the message getCause.

First, modify testInvalidSessionUrl to extract the cause from the SessionException instance. As part of the test verification, ensure that the cause of the exception is the reason expected.

 public void testInvalidSessionUrl() {    final String url = "httsp://course.langrsoft.com/cmsc300";    try {       session.setUrl(url);       fail("expected exception due to invalid protocol in URL");    }    catch (SessionException expectedException) {       Throwable cause = expectedException.getCause();       assertEquals(MalformedURLException.class, cause.getClass());    } } 

The assertEquals statement ensures that the class of the cause is Malformed-URLException. The code to make this comparison demonstrates some reflective capabilities of Javathe ability of the language to dynamically derive information about types and their definitions at runtime. I will explain reflection capabilities in further depth in Lesson 12.

In short, you can send all objects the message getClass, which returns an appropriate class constant. A class constant is a class name followed by .class. MalformedURLException.class is a class constant that represents the Malformed-URLException class.

The test will fail: If no cause is explicitly set, getCause returns null. You will first need to modify SessionException to capture the cause upon construction:

 package studentinfo; public class SessionException extends Exception {    public SessionException(Throwable cause) {       super(cause);    } } 

You can then change the production code to embed the cause in the SessionException instance.

 public void setUrl(String urlString) throws SessionException {    try {       this.url = new URL(urlString);    }    catch (MalformedURLException e) {       log(e);       throw new SessionException(e); // < here's the change    } } 



Agile Java. Crafting Code with Test-Driven Development
Agile Javaв„ў: Crafting Code with Test-Driven Development
ISBN: 0131482394
EAN: 2147483647
Year: 2003
Pages: 391
Authors: Jeff Langr

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net