Chapter 15: Exception Handling

Download Report

Transcript Chapter 15: Exception Handling

Tues. Nov. 25

An exception is an unexpected error or
condition, such as
◦ You issue a command to read a file from a disk, but
the file does not exist there
◦ You attempt to write data to a disk, but the disk is
full or unformatted
◦ Your program asks for user input, but the user
enters invalid data
◦ The program attempts to divide a value by 0



These are the object-oriented methods to
manage such errors
Java has two basic classes of errors: Error
and Exception
Both of these classes descend from the
Throwable class, as shown next

Object
◦ Throwable
 Exception
 IOException
 Runtime Exception
 ArithmeticException
 IndexOutOfBoundsException

ArrayIndexOutOfBoundsException
 Others
 Error
 VirtualMachineError
 OutofMemoryError
 InternalError
 Others…




These are serious errors from which your
program cannot recover
Such as, a misspelled class name or a class
stored in the wrong folder
If the program cannot find the class, an Error
condition occurs
If the program runs out of memory, an Error
condition occurs



These are less serious errors that represent
unusual conditions that arise while the
program is running and from which the
program can recover
Examples include using an invalid array
subscript or performing certain illegal
arithmetic operations
Your program can determine the type of error
by examining the code of the error returned
by Java
C:\Java\Java xyz.java
error: cannot read xyz.java
1 error
C:\Java\>_

In this case there is no program code you
could write that could fix or prevent the
error message



When the program generates an exception
message, it produces a different type of
message
An exception message is one that could have
been prevented by writing specific methods
in the program
Consider the following program…
public class MathMistake
{
public static void main(String[] args)
{
int num = 13, denom = 0, result;
result = num / denom;
}
}
C:\Java\java MathMistake
Exception in thread “main”
java.lang.ArithmeticException: / by zero
at MathMistake.main<MathMistake.java:6>
C:\Java>_


The Exception is a java.lang.ArithmeticException
which is one of many subclasses of Exception
You are told the type of error as well as the line
number of the error




You can simply let the program terminate
The termination is abrupt and unforgiving
This might annoy the user
Or the termination could be disastrous such
as in an air traffic control situation

Consider the following arithmetic (division by
0) error and its various traditional ways of
handling the error
public class MathMistake
{
public static void main(String[] args)
{
int num = 13, denom = 0, result;
if(denom == 0)
System.exit(1);
result = num / denom;
}
}



When you use System.exit(), the current
application ends and control returns to the
operating system
The convention is to return a value of 1 if an
error is causing the termination; otherwise, a
value of 0 is returnedunder normal
termination
Using System.exit() circumvents displaying
the error message shown above because the
program ends before the the division by zero
occurs



When you write code to detect exceptions,
you ‘try’ a procedure that might cause an
error
A method that detects an exception ‘ throws
an exception,’ and the block of code that
processes the error ‘catches the exception.’
Programs that can handle exceptions are said
to be more fault tolerant and robust
◦ Fault-tolerant apps are designed so that they
continue to operate, possibly at a reduced level

When you create a segment of code in which
something might go wrong, you place the
code in a try block, which is a block of code
you attempt to execute while acknowledging
that an exception might occur








The keyword catch
An opening parenthesis
An Exception type
A name for an instance of the Exception type
A closing parenthesis
An opening curly brace
The statements that take the action you want
A closing curly brace
returnType methodName(optional arguments)
{
optional statements prior to code that is tried
try
{
//statements that might generate an exception
}
catch(Exception someException)
{
// actions to take if exception occurs
}
// optional statements that occur after try
}




In the slide above, someException represents
an object of the Exception class or any of its
subclasses
If an exception occurs during the execution
of the try block, the statements in the catch
block execute
If no exception occurs within the try block,
the catch block does not execute
Either way the statements following the catch
block execute normally
public class MathMistakeCaught
{
public static void main(String[] args)
{
int num = 13, denom = 0, result;
try
{
result = num / denom;
}
catch(ArithmeticException mistake)
{
System.out.println("Attempt to divide by zero!");
}
}
}

C:\Java>java MathMistakeCaught
Attempt to divide by zero!

C:\Java>


If you want to send error messages to a
different location from ‘normal’ you can use
System.err instead of System.out


Lots of different types of errors could have
occurred within the try block
You can have the system print the type of
error with the following code
public class MathMistakeCaught2
{
public static void main(String[] args)
{
int num = 13, denom = 0, result;
try
{
result = num / denom;
}
catch(ArithmeticException mistake)
{
System.out.println(mistake.getMessage());
}
}
}

Uses the getMessage() method to generate
the message that ‘comes with’ the caught
ArithmeticException argument to the catch
block
C:\Java>java MathMistakeCaught2
/ by zero
C:\Java>_
try
{
result = num / denom;
}
catch(ArithmeticException mistake)
{
result = num/1;
System.out.println(mistake.getMessage());
}

Holds a valid value—either the code in the try
block worked, or the code in the catch block
assigned a valid value to result if the try block
did not work

The catch blocks are written so that they look
like methods




You can place as many statements as you
need within a try block and you can catch as
man Exceptions as you want
However, the first such Exception will cause
the logic to leave the try block and to enter
the catch block
Thus, the first error-generating statement
throws an Exception
When a program contains multiple catch
blocks, they are examined in sequence until a
match is found for the type of Exception that
occurred


Then, the matching catch block executes and
each remaining catch block is bypassed
For example, consider the code below
public class TwoMistakes
{
public static void main(String[] args)
{
int num[] = {4, 0, 0};
try
{
num[2] = num[0] / num[1];
num[2] = num[3] / num[0];
}
catch(ArithmeticException e)
{
System.out.println("Arithmetic error");
}
catch(IndexOutOfBoundsException e)
{
System.out.println("Out of bounds error");
}
System.out.println("End of program");
}
}

C:\Java\java TwoMistakes
Arithmetic error
End of program

C:\Java>_



Note that the second statement in the try
block is never attempted and the second
catch block is skipped
public class TwoMistakes2
{
public static void main(String[] args)
{
int num[] = {4, 0, 0};
try
{
num[2] = num[0] / 10;
num[2] = num[3] / num[0];
}
catch(ArithmeticException e)
{
System.out.println("Arithmetic error");
}
catch(IndexOutOfBoundsException e)
{
System.out.println("Out of bounds error");
}
System.out.println("End of program");
}
}

C:\Java\java TwoMistakes2
Out of bounds error
End of program

C:\Java>_




Again, the try block is abandoned, the first
catch block is examined and found unsuitable
because it does not catch an
IndexOutOfBoundsException
The program proceeds to the second catch
block



The following program uses only one catch
block to catch both ArithmeticExceptions and
IndexOutOfBounds exceptions
The above exceptions are both subclasses of
Exception
Therefore, the catch blocks shown above can
be replaced with a single generic catch block,
as shown below
public class TwoMistakes3
{
public static void main(String[] args)
{
int num[] = {4, 0, 0};
try
{
num[2] = num[0] / num[1];
num[2] = num[3] / num[0];
}
catch( Exception e)
{
System.out.println(e.getMessage());
}
}
}



Will catch all exceptions
When either an arithmetic exception or array
index exception occurs, the thrown exception
is ‘promoted’ to an Exception error in the
catch block
Because an Exception is Throwable, you can
use the Throwable class getMessage() method



If you place a generic catch block first and
then specific catch blocks afterwards, the
specific catch blocks will possess code that is
unreachable because the generic catch block
will catch all exceptions before they can be
tested against specific catch blocks
Unreachable code statements are program
statements that can never execute under any
circumstances.
Try blocks should not throw more than four
exception types

finally blocks follow catch blocks and are
used to cleanup after try and catch blocks
regardless of whether an exception occurred
or not
Try
{
// statements of try
}
catch(Exception e)
{
// actions taken if exception was thrown
}
finally
{
// actions taken whether catch block executed or not
}



There is a System.exit(); statement in either
the try block or the catch block
An unplanned Exception occurs
When an unplanned Exception occurs, the
application is stopped and control is returned
to the operating system where the Exception
is handled—the program is abandoned
try
{
// Open the file
// Read the file
// Place the file data in an array
// Calculate an average from the data
// Display the average
}
catch(IOException e)
{
// Issue an error message
// System exit
}
finally
{
// if file is open, close it
}


The advantage of exception handling is that it
enables you to create a fix-up for the
exception and to permit the program to
continue
It also simplifies exception handling overall
call methodA()
If methodA() worked
{
call methodB()
if methodB() worked
{
call methodC()
if methodC() worked
Everything is OK so print final result
else
Set errorCode to ‘C’
}
else
Set errorCodee to ‘B”
}
else
Set errorCode to ‘A’
}
try
{
call methodA() and maybe throw an exception
call methodB() and maybe throw an exception
call methodC() and maybe throw an exception
}
Catch(methodA()’s error)
{
set errorCode to ‘A’
}
Catch(methodB()’s error)
{
set errorCode to ‘B’
}
Catch(methodC()’s error)
{
set errorCode to ‘C’
}




Logic is much simplier
Reusability of the method is much better
If a method throws an exception that will not
be caught inside the method, you must use
the keyword throws followed by an Exception
type in the method header
Consider the following code…
Public class PriceList
{
private static final double[] price =
{15.99,27.88,34.56,45.89};
public static void displayPrice(int item)
throws IndexOutOfBoundsException
{
System.out.println(“The price is” + price[item];
}
}
public class PriceListApplication1
{
public static void main(String[] args)
{
int item = 4;
try
{
PriceList.displayPrice(item);
}
catch(IndexOutOfBoundsException e)
{
System.out.println("Price is $0");
}
}
}
import javax.swing.*;
public class PriceListApplication2
{
public static void main(String[] args)
{
int item = 4;
try
{
PriceList.displayPrice(item);
}
catch(IndexOutOfBoundsException e)
{
while(item < 0 || item > 3)
{
String answer = JOptionPane.showInputDialog(null,
"Please reenter a value 0, 1, 2 or 3");
item = Integer.parseInt(answer);
}
PriceList.displayPrice(item);
}
System.exit(0);
}
}

Java’s exceptions come in two types:
◦ Checked exceptions—the type programmers
should be detecting and recovering from
◦ Unchecked exceptions—don’t mess with these

Programmers usually cannot anticipate
unchecked exceptions, which are
◦ Hardware failures
◦ Logic errors
◦ [programs cannot fix these]

Programs can only fix checked exceptions
while it is executing



All exceptions that you specifically throw are
checked exceptions
These descend from the Exception class
These are not runtime exceptions



Catch it in the method
Declare the exception in your method
header’s throws clause
If you use the latter, then any programmer
who uses your method must do one of the
following:
◦ Catch and handle the exception
◦ Declare the exception in the throws clause of their
method




The method’s return type
The type and number of arguments the
method requires
The type and number of Exceptions the
method throws
Why don’t you have to know what other
methods the method extends from and what
other methods the method implements?



When an exception occurs, Java will trace
back through the call stack looking for a
catch in each of the methods
If none is found, control returns to the
operating system
Consider the following program…
import javax.swing.*;
public class DemoStackTrace
{
public static void main(String[] args)
{
methodA(); // line 6
}
public static void methodA()
{
System.out.println("In methodA()");
methodB(); // line 11
}
public static void methodB()
{
System.out.println("In methodB()");
methodC(); // line 16
}
public static void methodC()
{
System.out.println("In methodC()");
JFrame frame = null;
frame.setVisible(true); // line 22
}
}
C:\Java>java DemoStackTrace
In methodA()
In methodB()
In methodC()
Exception in thread “main” java.lang.nullPointerException
at DemoStrackTrace.methodC(DemoStackTrace.java:22)
at DemoStrackTrace.methodB(DemoStackTrace.java:16)
at DemoStrackTrace.methodA(DemoStackTrace.java:11)
at DemoStrackTrace.main(DemoStackTrace.java:6)

C:\Java>
import javax.swing.*;
public class DemoStackTrace2
{
public static void main(String[] args)
{
methodA(); // line 6
}
public static void methodA()
{
System.out.println("In methodA()");
try
{
methodB(); // line 13
}
catch(RuntimeException e)
{
System.out.println("In methodA() - The stack trace:");
e.printStackTrace();
}
System.out.println("Method ends normally.");
System.out.println("Application could continue here.");
}
public static void methodB()
{
System.out.println("In methodB()");
methodC(); // line 26
}
public static void methodC()
{
System.out.println("In methodC()");
JFrame frame = null;
frame.setVisible(true); // line 32
}
}
C:\Java>java DemoStackTrace
In methodA()
In methodB()
In methodC()
In methodA() – The stack trace:
java.lang.nullPointerException
at DemoStrackTrace.methodC(DemoStackTrace.java:32)
at DemoStrackTrace.methodB(DemoStackTrace.java:26)
at DemoStrackTrace.methodA(DemoStackTrace.java:13)
at DemoStrackTrace.main(DemoStackTrace.java:6)
Method ends normally.
Application could continue here.

C:\Java>


Java provides over 40 categories of
Exceptions that you can use in your programs
But Java cannot anticipate all of the possible
exceptions you might want to catch
◦ Ex. A negative bank balance
◦ Ex. Someone tries to access your email


To create your own throwable Exception, you
must extend a subclass of Throwable.
The class Throwable has two subclasses—
Exception and Error




Exception() – constructs a new exception with
null as its detail message
Exception(String message) – constructs a new
exception with the specified detail message
Exception(String message, Throwable cause) –
constructs a new exception with the specified
detail message and cause
Exception(Throwable cause) – constructs a
new exception with the specified cause







public class HighBalanceException extends
Exception
{
public HighBalanceException()
{
super("Customer balance is high");
}
}













public class CustomerAccount
{
private int acctNum;
private double balance;
public static double HIGH_CREDIT_LIMIT = 20000.00;
public CustomerAccount(int num, double bal) throws
HighBalanceException
{
acctNum = num;
balance = bal;
if(balance > HIGH_CREDIT_LIMIT)
throw(new HighBalanceException());
}
}


























import javax.swing.*;
public class UseCustomerAccount
{
public static void main(String[] args)
{
int num;
double balance;
String input;
input = JOptionPane.showInputDialog(null, "Enter account number");
num = Integer.parseInt(input);
input = JOptionPane.showInputDialog(null, "Enter balance due");
balance = Double.parseDouble(input);
try
{
CustomerAccount ca = new CustomerAccount(num, balance);
JOptionPane.showMessageDialog(null, "Customer #" +
num + " has a balance of $" + balance);
}
catch( HighBalanceException hbe)
{
JOptionPane.showMessageDialog(null, "Customer #" +
num + " has a balance higher than the credit limit");
}
System.exit(0);
}
}




Assertions are Java language features that help
you detect logic errors that do not create runtime
errors, but do produce results that are wrong
You use assert statement to create an assertion
The syntax is…
Assert booleanExpression : optionalErrorMessage
import javax.swing.*;
class PayRaise
{
public static void main(String[] args)
{
double oldPay = 0;
double newPay = 0;
final double INCREASE = 0.04;
final double TAXRATE = 0.28;
final double HRSPERWEEK = 40;
final double INSURANCE = 140.00;
String entry;
entry = JOptionPane.showInputDialog(null,
"Enter old pay per hour");
oldPay = Double.parseDouble(entry);
newPay = oldPay + oldPay * INCREASE;
assert oldPay < newPay:
"\nOld Pay is " + oldPay +
"\nNew pay is $" + newPay +
"\nNew pay should be more than old pay";
newPay = (newPay * HRSPERWEEK) (newPay * TAXRATE) - INSURANCE;
assert oldPay < newPay:
"Old Pay is " + oldPay +
"\nNew pay is $" + newPay +
"\nNew pay should be more than old pay";
JOptionPane.showMessageDialog(null,
"New net pay is $" + newPay + " per week");
System.exit(0);
}
}
C:\Java>javac –source 1.6 PayRaise.java
C:\Java>java –ea Payraise
Exception in thread “main”
java.lang.AssertioniError:
Old Pay is $12.48
New pay is $0.0
New pay should be more than old pay
At PayRaise.main<PayRaise.java:18>
C:\Java>
public class CustomerAccount
{
private int acctNum;
private double balance;
public static double HIGH_CREDIT_LIMIT = 20000.00;
public CustomerAccount(int num, double bal) throws
HighBalanceException
{
acctNum = num;
balance = bal;
if(balance > HIGH_CREDIT_LIMIT)
throw(new HighBalanceException());
}
}
import javax.swing.*;
public class DemoStackTrace
{
public static void main(String[] args)
{
methodA(); // line 6
}
public static void methodA()
{
System.out.println("In methodA()");
methodB(); // line 11
}
public static void methodB()
{
System.out.println("In methodB()");
methodC(); // line 16
}
public static void methodC()
{
System.out.println("In methodC()");
JFrame frame = null;
frame.setVisible(true); // line 22
}
}