Close
Register
Close Window

Masters of Engineering Bridge Course

Chapter 7 Testing and Exceptions

Show Source |    | About   «  7.1. Java Unit Testing   ::   Contents   ::   7.3. Objects, Enums, and UML Diagrams  »

7.2. More on Exceptions

7.2.1. Objectives

Upon completion of this module, students will be able to:

  • Understand the purpose Exceptions and Exception handling

  • Understand and use try-catch-finally blocks to handle exceptions

  • Throw exceptions in a method

  • Implement and test Exception handling code

7.2.2. [9:31] Intro to Exceptions Video

TODO: fix URLS.

Intro to Exceptions.pptx

7.2.2.1. Reflecting on Checked and Runtime(Unchecked) Exceptions

7.2.2.1.1. Checked Exceptions:

  • These are exception that are “checked” at compile-time

  • Checked Exceptions MUST be either

    • caught (using try-catch) or

    • declared in the method in which it is thrown (using throws) – see example below

public void myMethod() throws IOException {

       // programming statements

}
  • If a Checked Exception is not handled or thrown the compiler will report a compilation error when attempting to compile the program in question

Examples of Checked Exceptions include: ClassNotFoundException, FileNotFoundException, IOException, and NoSuchMethodException

7.2.2.1.2. Runtime Exceptions aka Unchecked Exceptions:

  • These are exception that are NOT “checked” at compile time

  • Unlike Checked Exceptions any code which may potentially throw a Runtime (Unchecked) Exception will compile without a problem, the developer must therefore consider the likelihood of such exceptions occurring and prepare the program accordingly

  • Examples of Runtime (Unchecked) Exceptions include: ArithmeticException, ArrayIndexOutOfBoundsException, ClassCastException, and NullPointerException

7.2.2.1.3. Note:

Many students encounter NullPointerExceptions throughout the various projects and labs. Always remember that these occur when your code tries to access an object that is null. Remember as well that an object may be null if the object was declared but never instantiated OR became null at some point throughout its life. One easy way to troubleshoot such exceptions is to determine if the object was, in fact, instantiated or not. Simply review the body of code where you believe the object was instantiated, then assess and test to confirm that that body of code did execute as expected.

7.2.2.3. Checkpoint 1

7.2.3. [7:16] Exception Handling with try, catch, and finally video

7.2.3.1. Handling the Exception now - Summary

To implement Exception Handling within a body of code you must use the try-catch-finally block

You may use a single catch block, such as below:

try{

}

catch(ExceptionType eName){

}

or multiple catch blocks, such as the example below:

When using multiple catch blocks the order of how the Exception handlers are implemented matters.

The code should be ordered with the handler for the most specific Exception defined first, eventually progressing to the definitions for the most general exceptions.

For example:

try{


}

catch(NumberFormatException nfe){


}

catch(Exception e){

}

We may also use the optional finally block. For example:

try{

}

catch(Exception e){


}

finally{


}

Note that you can also use the optional finally block with a try but without a catch, such as below

try{

}

finally{

}

7.2.3.2. Handling the Exception later on (postponing or deferring handling of the Exception)

As mentioned above there are times when it is appropriate to implement code that catches Exceptions that occur within it, essentially handling the Exception within the body of code that may cause it. At other times it may be more appropriate to postpone handling of a given Exception, deferring or passing the responsibility of handling it to some other calling code (client code). This option is appropriate when there is an expectation or agreement that the calling code (client code) may be better suited to deal with the Exception. Recall that client code called the method that caused an Exception, it is reasonable to assume therefore that such client code may be better suited to determining the best way of responding to the Exceptional event.

To postpone or defer Exception Handling to client code we add a throws clause to the method declaration for the potentially risky method (the one that could cause an Exception). The throws clause must follow the method name and parentheses, within this clause we must use the throws keyword and provide a comma-separated list of all the exceptions thrown by that method (see example below).

public void riskyCodeThatWantsToDefer ( ) throws IOException, NumberFormatException  {

   // some code

}

The throws clause declares the exceptions that may occur during the program execution, essentially informing calling/client code that it needs to prepare itself to handle such occurrences, either by implementing a try-catch itself OR deferring to other calling/client code by adding a throws clause to the method declaration.

For example the method below calls the risky code, it would therefore be notified that it should expect either a IOException, NumberFormatException to come its way and to prepare itself accordingly.

public  void callingMethod() {

     riskyCodeThatWantsToDefer();

 }

The compilation error message (Unhandled exception type SomeException) will occur if the client code, the callingMethod, does not include code which catches or throws the Exceptions that riskyCodeThatWantsToDefer has declared that it throws.

7.2.3.3. Related Resources

Download the sample project to run and explore on your own in eclipse:

TODO: fix URLS.

 CS2-ExExceptionHandling.zip

This `link <>`_ will direct you to the steps to `download and import <>`_ previously written code into the Eclipse environment.

7.2.4. Exception Examples - Basic to Complex

7.2.4.1. [12:05] Basic “try, catch” example Video

7.2.4.2. [14:13] Tracing through a “try, catch” example with multiple catch blocks

7.2.4.3. [12:33] Example using “try, catch, and finally” blocks Video

7.2.4.4. Related Resources

Download the sample project to run and explore on your own in eclipse:

TODO: fix URLS.

 CS2-ExExceptionHandling.zip

This `link <>`_ will direct you to the steps to `download and import <>`_ previously written code into the Eclipse environment.

7.2.5. Implementing and Testing Exceptions

** “If you throw exceptions in your methods, then you should catch them in your testing” **

For this course we will mostly adopt the exception handling approach that uses try-catch blocks in combination with the throw statement.

When implementing methods with exception-prone code you are to implement code within your methods which checks for unusual conditions (possible exception events) BEFORE* allowing the execution of risky code (code which may throw an exception). You must then implement **try-catch blocks within test classes to confirm that the correct Exceptions were thrown by the failing code. Within test classes you must also create the necessary conditions for the exceptions to be thrown.

Note that these checks could be accomplished through the use of try-catch blocks or conditional statements (for example the if statement).

Your code should function as follows:

If the checks pass then code execution should proceed normally, allowing the exception-prone code to execute If the checks fail then the method should throw an Exception intentionally

7.2.5.1. Throwing an Exception

Any code has the ability to throw an exception under the right conditions. You may intentionally throw an exception with the throw statement. You may throw any of the many exceptions that exist, or more specifically, any of the classes that are descendants of the Throwable class.

If necessary you may also create your own custom exception classes to cater for unexpected scenarios not already catered for by the standard Java exception classes.

To throw an exception you must provide the throw statement an instance of a throwable object.

For example if you wished to throw just a general exception you could use the following statement:

throw new Exception();

If, on the other hand, you wished to throw a specific exception, such as a NumberFormatException, you could use the following statement:

throw new NumberFormatException();

// or

throw new NumberFormatException( "this is some message" );

All that is required is an understanding of the Constructors available for the exception you wish to throw.

7.2.5.1.1. Example

The following MyCalculator class provides client code with access to the methods sum() and div(). Both add() and div() each accept two String parameters representing two integers. The add() method returns the result of adding the int equivalent of the two parameters while the div() method returns the result of dividing the int equivalent of the two parameters.

public class MyCalculator {

 public int sum(String num1String, String num2String) {
     int sum = 0;
     try {
         int num1 = Integer.parseInt(num1String);
         int num2 = Integer.parseInt(num2String);

         sum = num1 + num2;
     }
     catch (NumberFormatException nfe) {
         throw new NumberFormatException();
     }
     return sum;
 }


 public int div(String num1String, String num2String) {
     int div = 0;
     try {
         int num1 = Integer.parseInt(num1String);
         int num2 = Integer.parseInt(num2String);
         div = num1 / num2;
     }
     catch (NumberFormatException nfe) {
         throw new NumberFormatException();
     }
     catch (ArithmeticException ae) {
         throw new ArithmeticException();
     }
     return div;
 }

}

Review the MyCalculator class using the code above or the link to the code:

TODO: fix URLS.

 CS2-ExExceptionHandlingWithThrow.zip

Note how the class uses the statements:

throw new NumberFormatException();

And

throw new ArithmeticException();

To intentionally throw each Exception when appropriate.

When writing your test class you must therefore use a try-catch block to check if your method code has thrown the right exception. In your try block, you should call the method that results in an exception being thrown. The catch block should catch the exception thrown. You must then assert that the exception exists, is the correct exception, and (if applicable) contains the correct message.

Observe the partially implemented test class MyCalculatorTest. This class will be used to evaluate the MyCalculator class to determine if the class threw the correct exception for each test case.

Note how the test class adopts the approach described above, declaring an exception object that matches the exception being tested. Initially this exception object is set to null and only updated within the catch block.

public class MyCalculatorTest extends student.TestCase {

    MyCalculator calc;

    public void setUp() {
        calc = new MyCalculator();
    }


    /**
     * Tests to ensure Sum throws a NumberFormatException
     * if the first parameter is not a number
     */
    public void testSumNFEException() {
        NumberFormatException myNFE = null;

        try {
            calc.sum("2hello", "3");
        }
        catch (NumberFormatException nfe) {
            myNFE = nfe;
        }
        assertNotNull(myNFE);
    }


    /**
     * Tests to determine if div throws an ArithmeticException
     * if one of the parameters is 0
     */
    public void testDivArithException() {
        ArithmeticException myAE = null;
        try {
            calc.div("2", "0");
        }
        catch (ArithmeticException ae) {
            myAE = ae;
        }
        assertNotNull(myAE);
    }

}

Again, you can review this code here:

TODO: fix URLS.

 CS2-ExExceptionHandlingWithThrow.zip

7.2.5.2. Checkpoint 2

   «  7.1. Java Unit Testing   ::   Contents   ::   7.3. Objects, Enums, and UML Diagrams  »

nsf
Close Window