Exception Handling

advertisement
Exception Handling
Lecture Objectives
• To learn how to throw exceptions
• To be able to design your own exception
classes
• To understand the difference between checked
and unchecked exceptions
• To learn how to catch exceptions
• To know when and where to catch an exception
The finally clause
• Exception terminates current method
• Danger: Can skip over essential code
Example:
reader = new FileReader(filename);
Scanner in = new Scanner(reader);
readData(in);
reader.close();
// May never get here
The finally clause (Cont’d)
• Must execute reader.close() even if
exception happens
• Use finally clause for code that must be
executed "no matter what"
The finally clause (Cont’d)
FileReader reader = new FileReader(filename);
try {
Scanner in = new Scanner(reader);
readData(in);
}
finally {
reader.close(); // if an exception occurs, finally clause
// is also executed before exception is
// passed to its handler
}
The finally clause (Cont’d)
• Executed when try block is exited in any of
three ways:
 After last statement of try block
 After last statement of catch clause, if this try block
caught an exception
 When an exception was thrown in try block and not
caught
• Recommendation: don't mix catch and
finally clauses in same try block
Syntax: The finally clause
Try {
statement
statement
. . .
}
finally {
statement
statement
. . .
}
Syntax: The finally clause (Cont’d)
Example:
FileReader reader = new FileReader(filename);
try {
readData(reader);
}
finally {
reader.close();
}
Purpose:
To ensure that the statements in the finally clause are executed
whether or not the statements in the try block throw an exception.
Designing Your Own Exception Types
• You can design your own exception types–
subclasses of Exception or
RuntimeException
if (amount > balance) {
throw new InsufficientFundsException(
" withdrawal of " + amount + " exceeds balance of "
+ balance);
}
• Make it an unchecked exception–programmer
could have avoided it by calling the method
getBalance() first
Continued…
Designing Your Own Exception Types (Cont’d)
•
Extend RuntimeException or one of its
subclasses
•
Supply two constructors
1. Default constructor
i. It is good practice to include a default message in the
default constructor
2. A constructor that accepts a message string describing
“current-object-info” and/or reason for exception
Designing Your Own Exception Types (Cont’d)
public class InsufficientFundsException extends RuntimeException{
public InsufficientFundsException() {
super("Insufficient Funds Exception");
}
public InsufficientFundsException(String message) {
super(message);
}
}
Using the getMessage Method
• Every exception has a String instance
variable that contains some message
 This string typically identifies the reason for the
exception
• This is the string used for the value of the
string instance variable
 Therefore, the method call e.getMessage() returns
this string
Using the getMessage Method
. . . // method code
try
{
. . .
throw new InsufficientFundsException(
" withdrawal of " + amount + " exceeds balance of "
+ balance);
. . .
}
catch(InsufficientFundsException e)
{
String message = e.getMessage();
System.out.println(message);
} . . .
Preserve getMessage
• For all predefined exception classes, getMessage returns
the string that is passed to its constructor as an
argument
 Or it will return a default string if no argument is used with the
constructor
• This behavior must be preserved in all programmerdefined exception class
 A constructor must be included having a string parameter whose
body begins with a call to super
 The call to super must use the parameter as its argument
 A no-argument constructor must also be included whose body
begins with a call to super
 This call to super must use a default string as its argument
The Method printStackTrace()
• Used to determine the order in which the
methods were called and where the
exception was handled
The Method printStackTrace() (Cont’d)
import java.io.*;
public class PrintStackTraceExample1 {
public static void main(String[] args) {
try {
methodA();
}
catch (Exception e) {
System.out.println(e.toString()
+ " caught in main");
e.printStackTrace();
}
}
Continued…
The Method printStackTrace() (Cont’d)
public static void methodA() throws Exception {
methodB();
}
public static void methodB() throws Exception {
methodC();
}
public static void methodC() throws Exception {
throw new Exception("Exception generated "
+ "in method C");
}
}
Continued…
The Method printStackTrace() (Cont’d)
• Sample Run:
java.lang.Exception: Exception generated in method C caught in main
java.lang.Exception: Exception generated in method C
at PrintStackTraceExample1.methodC
(PrintStackTraceExample1.java:30)
at PrintStackTraceExample1.methodB
(PrintStackTraceExample1.java:25)
at PrintStackTraceExample1.methodA
(PrintStackTraceExample1.java:20)
at PrintStackTraceExample1.main
(PrintStackTraceExample1.java:9)
Effective Design
• Unfixable Error: If possible, it’s better to terminate
the program abnormally than to allow the error to
propagate.
• Normal versus Exceptional Code: The exception
handler --- the catch block --- is distinct from the
(normal) code that throws the exception --- the try
block.
• Using an Exception: If your exception handler is not
significantly different from Java’s, let Java handle it.
Effective Design (Cont’d)
• Handling Exceptions.
 Report the exception and terminate the program;
 Fix the exceptional condition and resume normal
execution.
 Report the exception to a log and resume execution.
• Program Development. Exceptions help identify design
flaws during program development.
• Report and Resume. Failsafe programs should report the
exception and resume.
Effective Design (Cont’d)
• Defensive Design. Anticipate potential problems,
especially potential input problems.
• Fixing an Exception. Handle fixable exceptions locally.
This is both clearer and more efficient.
• Library Exception Handling. Many library classes leave
exception handling to the application.
• Truly Exceptional Conditions. Use exceptions to handle
truly exceptional conditions, not for expected conditions.
Summary of Important Points
• In Java, when an error occurs, you throw an Exception which is
caught by exception handler code . A throw statement --- throw new
Exception() --- is used to throw an exception.
• A try block is contains one or more statements that may throw an
exception. Embedding a statement in a try block indicates your
awareness that it might throw an exception and your intention to
handle the exception.
Summary of Important Points (Cont’d)
• Checked exceptions must be caught or declared by the
method in which they occur.
• Unchecked exceptions (subclasses of RuntimeException)
are handled by Java if they are not caught in the
program.
• A catch block contains statements that handle the
exception that matches its parameter.
• A catch block can only follow a try block.
• There may be more than one catch block for each try
block.
Summary of Important Points (Cont’d)
• The try/catch syntax separates the normal parts of an
algorithm from special exceptional handling code.
• A method stack trace is a trace of a program’s method calls -Exception.printStackTrace().
• Static scoping: how the program is written. Depends on
declarations and definitions.
• Dynamic scoping: how the program is executed. Depends on
method calls.
Summary of Important Points (Cont’d)
• Finding a Catch Block: Search upward through the static scope,
and backward through the dynamic scope.
• The Java Virtual Machine handles unchecked exceptions not
caught by the program.
• Many Java library methods throw exceptions when an error
occurs.
• Example: Java's integer division operator will throw an
ArithmeticException if an attempt is made to divide by zero.
Summary of Important Points (Cont’d)
• Four ways to handle an exception:
 Let Java handle it.
 Fix the problem and resume the program.
 Report the problem and resume the program.
 Print an error message and terminate.
• The (optional) finally block contains code that will be executed whether
an exception is raised or not.
• Exceptions should be used for exception truly exceptional conditions,
not for normal program control.
• User-defined exceptions can extend the Exception class or one of its
subclasses.
A Complete Program
•
Program:





Asks user for name of file
File expected to contain data values
First line of file contains total number of values
Remaining lines contain the data
Typical input file:
3
1.45
-2.1
0.05
A Complete Program (Cont’d)
• What can go wrong?
 File might not exist
 File might have data in wrong format
• Who can detect the faults?
 FileReader constructor will throw an exception
when file does not exist
 Methods that process input need to throw exception if
they find error in data format
Continued…
A Complete Program (Cont’d)
• What exceptions can be thrown?
 FileNotFoundException can be thrown by
FileReader constructor
 IOException can be thrown by close method of
FileReader
 BadDataException, a custom checked exception
class
Continued…
A Complete Program (Cont’d)
• Who can remedy the faults that the
exceptions report?
 Only the main method of DataSetTester program
interacts with user
• Catches exceptions
• Prints appropriate error messages
• Gives user another chance to enter a correct file
File DataSetTester.java
01:
02:
03:
04:
05:
06:
07:
08:
09:
10:
11:
12:
13:
14:
15:
16:
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Scanner;
public class DataSetTester
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
DataSetReader reader = new DataSetReader();
boolean done = false;
while (!done)
{
try
{
Continued…
File DataSetTester.java
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
System.out.println("Please enter the file name: ");
String filename = in.next();
double[] data = reader.readFile(filename);
double sum = 0;
for (double d : data) sum = sum + d;
System.out.println("The sum is " + sum);
done = true;
}
catch (FileNotFoundException exception)
{
System.out.println("File not found.");
}
catch (BadDataException exception)
{
Continued…
System.out.println
("Bad data: " + exception.getMessage());
File DataSetTester.java
33:
34:
35:
36:
37:
38:
39:
40: }
}
catch (IOException exception)
{
exception.printStackTrace();
}
}
}
The readFile method of the
DataSetReader class
• Constructs Scanner object
• Calls readData method
• Completely unconcerned with any exceptions
Continued…
The readFile method of the
DataSetReader class
• If there is a problem with input file, it simply
passes the exception to caller
public double[] readFile(String filename)
throws IOException, BadDataException
// FileNotFoundException is an IOException
{
FileReader reader = new FileReader(filename);
try {
Scanner in = new Scanner(reader);
readData(in);
}
Continued…
The readFile method of the
DataSetReader class
finally {
reader.close();
}
return data;
}
The readFile method of the
DataSetReader class
• Reads the number of values
• Constructs an array
• Calls readValue for each data value
private void readData(Scanner in) throws BadDataException {
if (!in.hasNextInt())
throw new BadDataException("Length expected");
int numberOfValues = in.nextInt();
data = new double[numberOfValues];
for (int i = 0; i < numberOfValues; i++)
readValue(in, i);
if (in.hasNext())
throw new BadDataException("End of file expected");
}
The readFile method of the
DataSetReader class
•
Checks for two potential errors
1. File might not start with an integer
2. File might have additional data after reading all
values
•
Makes no attempt to catch any exceptions
The readFile method of the
DataSetReader class
private void readValue(Scanner in, int i)
throws BadDataException
{
if (!in.hasNextDouble())
throw new BadDataException("Data value expected");
data[i] = in.nextDouble();
}
Scenario
1. DataSetTester.main calls
DataSetReader.readFile
2. readFile calls readData
3. readData calls readValue
4. readValue doesn't find expected value
and throws BadDataException
5. readValue has no handler for exception
and terminates
Continued…
Scenario
6. readData has no handler for exception
and terminates
7. readFile has no handler for exception
and terminates after executing finally
clause
8. DataSetTester.main has handler for
BadDataException; handler prints a
message, and user is given another chance
to enter file name
File DataSetReader.java
01:
02:
03:
04:
05:
06:
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;
/**
Reads a data set from a file. The file must have
// the format
numberOfValues
value1
value2
. . .
07:
08:
09:
10:
11: */
12: public class DataSetReader
13: {
Continued…
File DataSetReader.java
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
/**
Reads a data set.
@param filename the name of the file holding the data
@return the data in the file
*/
public double[] readFile(String filename)
throws IOException, BadDataException
{
FileReader reader = new FileReader(filename);
try
{
Scanner in = new Scanner(reader);
readData(in);
}
finally
{
reader.close();
}
Continued…
File DataSetReader.java
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
return data;
}
/**
Reads all data.
@param in the scanner that scans the data
*/
private void readData(Scanner in) throws BadDataException
{
if (!in.hasNextInt())
throw new BadDataException("Length expected");
int numberOfValues = in.nextInt();
data = new double[numberOfValues];
for (int i = 0; i < numberOfValues; i++)
readValue(in, i);
Continued…
File DataSetReader.java
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
if (in.hasNext())
throw new BadDataException("End of file expected");
}
/**
Reads one data value.
@param in the scanner that scans the data
@param i the position of the value to read
*/
private void readValue(Scanner in, int i)
throws BadDataException
Continued…
{
File DataSetReader.java
60:
61:
62:
63:
64:
65:
66: }
if (!in.hasNextDouble())
throw new BadDataException("Data value expected");
data[i] = in.nextDouble();
}
private double[] data;
Download