|
Exceptions
An Introduction with Examples in Java |
|
Prof. David Bernstein |
| Computer Science Department |
| bernstdh@jmu.edu |
/**
* 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;
}
}
String
into a double?
double values are legitimate return values
there is no special value that can be used.return statement (with or without a value
to return)throw statement
(which must pass back a Throwable object)Throwable should
be used)void)throws
clause (that specifies the exception)
In the following example, a throw statement is used
for an alternative return and the return statement
is used for a normal return.
/**
* 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);
}
try block is used to indicate the code that
should be executed when the method returns normallycatch block (which is passed a
Throwable) is used to indicate the code that
should be executed when the method returns "abnormally"try-catch Statementtry-catch Statement (cont.)
/**
* 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!");
}
}
}
}
try-catch Statement (cont.)
/**
* 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);
}
}
catch Portion
catch(NumberFormatException nfe) { total += DEFAULT; }
NumberFormatException object that this statement
is going to "catch" and name nfe.
try-catch
throws clause in the declaration)
/**
* 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;
}
}
/**
* 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 Blockscatch Block:
catch blocks (but it is better to
use a logger)main()?
catch blocks that are in
the main() method
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.
The following two fragments have very different behavior.
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");
}
}
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");
}
/**
* 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!");
}
}
}
try-catch BlocksparseInt
generated the exception in the previous
example?try-catch statements
try-catch Blocks (cont.)
/**
* 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!");
}
}
}
ArrayIndexOutOfBoundsException so I'll fix it by
adding a try-catch block.")throws clause in its declaration{exceptions=name[,...]}
after the return type of the method to indicate that
exceptions are thrown