JMU
Exceptions
An Introduction with Examples in Java


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Motivation
Motivation (cont.)

An Example that Uses a Special Value

javaexamples/exceptions/PriceCalculator.java
/**
 * A simple PriceCalculator
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class PriceCalculator
{
    private double[] discounts = {0., 1., 5., 20., 100.};


    /**
     *  Apply a quantity-based discount
     */
    public double applyDiscount(double price, int quantity)
    {
        double       discountedPrice;
        int          i;

        discountedPrice = price;

        // Find the discount and adjust the price;
        i = discounts.length - 1;
        while (i >= 0)
        {
            if (quantity >= i)
            {
                discountedPrice = price - discounts[i];
                break;
            }

            --i;
        }

        // Return -1 to indicate a problem
        if (discountedPrice < 0) discountedPrice = -1;

        return discountedPrice;
    }

}
        
Questions
Exceptions - An Alternative Return Mechanism
The Signature of a Method with Both Return Mechanisms
A Method with Both Return Mechanisms

In the following example, a throw statement is used for an alternative return and the return statement is used for a normal return.

javaexamples/exceptions/EmailAddress.java (Fragment: getHost)
    /**
     * Return the host portion of an email address
     *
     * @param  address   A String representation of an email address
     * @return The host portion of the email address
     */
    public static String getHost(String address) throws IllegalArgumentException
    {
       int     index;
       
       index = address.indexOf("@");
       if ((index <= 0) || (index >= address.length()-1))
       {
          throw new IllegalArgumentException("Misplaced or missing @.");
       }
       else
       {
          return address.substring(index+1);
       }

       // Note: This is equivalent to:
       //
       // if ((index <= 0) || (index >= address.length()-1))
       // {
       //     throw new IllegalArgumentException("Misplaced or missing @.");
       // }
       //
       // return address.substring(index+1);
    }
        
Calling a Method that Uses Both Return Mechanisms
The try-catch Statement
The try-catch Statement (cont.)

Continuing the Earlier Example

javaexamples/exceptions/EmailProcessor.java
/**
 * A simple application that prints the host associated with an
 * email address
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class EmailProcessor
{
    /**
     * The entry-point of the application
     *
     * @param args  The command-line arguments
     */
    public static void main(String[] args)
    {
       String      host;
       
       if ((args != null) && (args.length > 0))
       {
          try
          {
             host = EmailAddress.getHost(args[0]);
             System.out.println("Host: "+host);
          }
          catch (IllegalArgumentException iae)
          {
             System.out.println("Try another email address!");
          }
       }
    }
}
        
The try-catch Statement (cont.)

An Example with a Loop

javaexamples/exceptions/GradeProcessor.java
/**
 * A simple application that prompts the processes 
 * grades (provided as command line arguments)
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class GradeProcessor
{
    /**
     * The entry-point of the application
     *
     * @param grades  The space-delimited grades
     */
    public static void main(String[] grades)
    {
       double         total;
       final double   DEFAULT = 50.0;       


       total = 0;       
       for (int i=0; i<grades.length; i++)
       {
          try
          {
             total += Double.parseDouble(grades[i]);
          } 
          catch (NumberFormatException nfe)
          {
             total += DEFAULT;
          }
       }

       System.out.printf("Average: %3.1f", total/grades.length);       
    }
}
        
A Closer Look at the catch Portion
Nerd Humor
Bonding
http://imgs.xkcd.com/comics/bonding.png
(Courtesy of xkcd)
Re-Throwing Exceptions
Re-Throwing Exceptions (cont.)

An Example

javaexamples/exceptions/Divider.java
/**
 * A simple utility class for integer division that
 * illustrates how exceptions can be re-thrown
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class Divider
{
    /**
     * Performs integer division
     *
     * @param num   The numerator
     * @param denom The denominator
     * @return      The result of the integer division
     * @throws      An ArithmeticException in case of a divide by zero
     */
    public int divide(int num, int denom) throws ArithmeticException
    {
        int     result;

        result = num / denom;
        return result;
    }
}
        
Handling Re-Thrown Exceptions

An Example

javaexamples/exceptions/DividerDriver.java
/**
 * A simple application that sequentially divides 
 * elements in an array.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class DividerDriver
{
    public static void main(String[] args)
    {
       Divider    d;
       int        i, ratio;
       int[]      numbers = {100,10,0,5,2,8,0,30};


       d = new Divider();

       for (i=0; i < numbers.length-1; i++) 
       {
          try 
          {
             ratio = d.divide(numbers[i], numbers[i+1]);
             System.out.println(numbers[i]+"/"+numbers[i+1]+"="+ratio);
          } 
          catch (ArithmeticException ae)
          {
             System.out.println("Couldn't calculate "+
                                numbers[i]+"/"+numbers[i+1]);
          }
       }
    }
}
        
Catch or Re-Throw?
Things to Avoid in Catch Blocks
A Common Mistake

Beginning programmers often make the following mistake when told that a method must throw an exception. For example, if they are told that the method they are writing must throw a NumberFormatException they add a throws NumberFormatException clause to the method declaration and do the following.

  try
  {
      d = Double.parseDouble(s);
  }
  catch (NumberFormatException nfe)
  {
      throw new NumberFormatException(); // throw nfe; is also bad
  }
  

Instead you should add a throws NumberFormatException clause to the method declaration and do the following.

  d = Double.parseDouble(s);
  

The only reason to include a throw statement in a catch block is if a different exception must be thrown.

Exception Handling with Nested Blocks

The following two fragments have very different behavior.

javaexamples/exceptions/NestedBlockExample.java (Fragment: 0)
       for (i=0; i < args.length; i++)
       {
          try
          {
             value = Double.parseDouble(args[i]);
             System.out.println(args[i]+" is a number");
          } 
          catch (NumberFormatException nfe)
          {
             System.out.println("Not a number");
          }
       }
        
javaexamples/exceptions/NestedBlockExample.java (Fragment: 1)
       try 
       {
          for (i=0; i < args.length; i++) 
          {
             value = Double.parseDouble(args[i]);
             System.out.println(args[i]+" is a number");
          }
       } 
       catch (NumberFormatException nfe)
       {
          System.out.println("Not a number");
       }
        
Handling Multiple Exceptions
Handling Multiple Exceptions

An Example

javaexamples/exceptions/Calculator.java
/**
 * A simple calculator.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 1.0
 */
public class Calculator
{
    /**
     * The entry point of the application.
     *
     * @param args  Syntax: left-operand operator right operand
     */
    public static void main(String[] args)
    {
       char           operator;
       int            left, result, right;

       try 
       {
          result = 0;

          left  = Integer.parseInt(args[0]);
          right = Integer.parseInt(args[2]);

          operator = args[1].charAt(0);
            
          switch (operator) 
          {
             case '+': 
                result = left + right;
                break;

             case '-': 
                result = left - right;
                break;

             case '/': 
                result = left / right;
                break;
          }
          System.out.println("Result: "+result);
       } 
       catch (ArithmeticException ae) 
       {
          System.out.println("Does not compute!");
       } 
       catch (NumberFormatException nfe) 
       {
          System.out.println("Non-numeric operand!");
       }
    }
}
        
Nested try-catch Blocks
Nested try-catch Blocks (cont.)

An Example

javaexamples/exceptions/CalculatorNested.java
/**
 * A simple calculator.
 *
 * This version illustrates how try-catch blocks can be nested.
 *
 * @author  Prof. David Bernstein, James Madison University
 * @version 2.0
 */
public class CalculatorNested
{
    /**
     * The entry point of the application.
     *
     * @param args  Syntax: left-operand operator right operand
     */
    public static void main(String[] args)
    {
       char           operator;
       int            left, result, right;

       result = 0;
       
       try
       {
           left  = Integer.parseInt(args[0]);
           try
           {
               right = Integer.parseInt(args[2]);
               operator = args[1].charAt(0);

               try
               {
                   switch (operator) 
                   {
                       case '+': 
                           result = left + right;
                           break;
                           
                       case '-': 
                           result = left - right;
                           break;
                           
                       case '/': 
                           result = left / right;
                           break;
                   }
                   System.out.println("Result: "+result);
               } 
               catch (ArithmeticException ae) 
               {
                   System.out.println("Does not compute!");
               } 
           }
           catch (NumberFormatException rnfe)
           {
               System.out.println("Right-side operand is non-numeric!");
           }
       }
       catch (NumberFormatException lnfe) 
       {
           System.out.println("Left-side operand is non-numeric!");
       }
    }
}
        
Two Additional Issues
Some "Familiar" Runtime Exceptions
Overuse
An Additional Detail in Java
Exceptions in UML