Held Wednesday, September 13, 2000
Summary
Today we discuss processes for handling errors. In Java, the
central error-handling mechanism is the exception.
Notes
- Homework 2 is due.
- How long did it take?
- I will not grade this assignment. However, I will provide
an answer key. I will also check that you made an attempt.
- Since you'll be working on a test next week, no homework is due
next week.
- Are there questions on phase
1 of the project?
- It's probably time to reflect on how the class is going.
- Are the introductory announcements helpful?
- Are you feeling comfortable with the pace?
- What kinds of sessions do you prefer?
- What can I do to help you get through the material?
Overview
- Notes on homework 2
- Errors in programs
- Techniques for handling errors
- Exceptions
- Dealing with exceptions
- Ignoring exceptions
- Indicating exceptions
- Creating new kinds of exceptions
- We'll spend a few minutes considering parts of today's
homework.
- First goal: Update
SimpleOutput
so that it can
print certain kinds of objects.
- What kinds of objects? Those that it makes sense to print.
- How can we express that notion? By creating a class or interface
that we call
Printable
.
- What should printable objects be able to do? Convert themselves
to strings.
- If we have that capability, the
print(Printable)
method in
SimpleOutput
is fairly easy to write.
- Next goal: Define
Printable
- Next goal: Try some examples, such as
PrintableFraction
.
- ...
- It's a given that things go wrong in programs.
- Sometimes, due to mistakes in input or logic, an invalid operation
is executed. This may be division by 0, an out-of-bounds array reference,
an incorrect input,
or a number of other things.
- Sometimes, due to problems beyond the programmer's control, the system
as a whole cannot respond and requested. (The power might go off;
a disk might become inoperative, etc.).
- Sometimes the programmer cannot identify errors in advance (for example,
a mail client won't necessarily be immediately able to verify that a
username or password are incorrect).
- What do we do about such problems?
- Only write correct code. Unfortunately, this doesn't work if there
is any communication with ``the outside world''.
- Let the program crash in such cases. Unfortunately, no one likes ot
use programs that crash. (Well, I know that Netscape and Microsoft
products are exceptions ....)
- Obviously, programmers need to do more. In considering potential
resolutions, we'll look at a few examples.
- What happens if someone enters an illegal move in our Othello game?
- If we decide to network our Othello game, what happens when one
player is unreachable?
- Consider the following program for computing an average grade.
What happens if the user enters no grades?
int DONE = -1;
boolean done = false;
int count = 0;
int sum = 0;
int grade;
while (!done) {
out.print("Enter grade: ");
grade = in.readInt();
if (grade != DONE) {
sum = sum + grade;
count = count + 1;
}
else {
done = true;
}
} // while
- One commonly-used technique is to check for errors before any operation
and then either skip the operation or recover from the error.
- In the case of the account/password, we might write
if (!Move.isvalid(playerColor,position)) {
out.println("Invalid move");
// ... try again
}
else {
// rest of program
}
- In the case of the average, we might write
if (count == 0) {
out.println("In order to compute an average grade, " +
"I must have at least one grade.");
}
else {
out.println("The average grade is " + sum/count);
}
- In the first case, we might even put the test into a loop.
// Assumption: Position 0,0 is invalid
Position pos = new Position(0,0);
while (!board.isValid(player,position) {
out.print("Enter row: ");
int row = in.readInt();
out.print("Enter column: ");
int col = in.readInt();
pos = new Position(row,col);
}
board.makeMove(player,position);
- We could set up our methods and operations to let us check whether
errors happened during operation.
- In the case of
readInt
, we might write
int row = in.readInt();
if (row == INVALID_VALUE)
out.println("Please enter a number");
//...
- In the case of our average, we might write
int average = sum / count;
if (INVALID_MATHEMATICAL_OPERATION) {
out.println("Could not compute the average.");
}
else {
out.println("The average grade is " + average);
}
- Both techniques are somewhat dangerous, particularly since there is
nothing to ensure that programmers use the technique.
- Java uses a variant of the second technique through a concept
known as exceptions. The designers of Java decided that
there should be a clear standard for handling erroneous or dangerous
conditions.
- Java is fairly strict about those exceptions because the designers
observed that most programmers
- assume that things will generally go right;
- ignore problems when developing developing solutions with the
expectation that ``I'll fix it once I get the 'real' stuff working''; and
- never get back to worrying about errors.
- In Java, possible problems are called exceptions, presumably because
they are exceptions to the rule.
- Exceptions are associated with methods. Each method that may lead to
errors lists the possible errors (exceptions) that may occur. Any
code that uses that method must indicate what to do when the errors
occur.
- For example, to say ``When you try to read an integer you may fail
because the user enters a non-number'', you might write something
like:
/**
* Read an integer.
*
* @exception NumberFormatException
* if the user enters something other than an integer
*/
public int readInt()
throws NumberFormatException
// ...
- When something goes wrong, a method throws an exception.
- Whenever you call a method that may throw an exception, you need to
handle it. You can
- Deal explicilty with the error.
- Pass the error on the method that called your method.
- The second is easier, but less useful. To pass an exception on, you
need to declare that your method
throws
the exception.
- For example,
public static void main(String[] args)
throws NumberFormatException
{
// ...
int row = in.readInt();
// ...
}
- To deal with exceptions, you need to do a few things.
- Determine the possible errors that can occur and decide how you
want to handle them. (This requires no coding; it is analysis
of the problem.)
- Note that you understand that errors can occur by placing the
potentially exceptional code in a
try
clause.
- For each possible exception, list what you want to do to recover
from the error in a
catch
clause.
- In Java,
try {
// stuff that may have problems
}
catch (ExceptionClass e1) {
// Handle one type of exception
}
catch (AnotherExceptionClass e2) {
// Handle another type of exception
}
finally {
// Clean up code that is always executed.
}
- For example,
public static void main(String[] args) {
// ...
int row = -1;
while (row < 0) {
try {
row = in.readInt();
}
catch (NumerFormatException e) {
out.println("Not a number");
}
} // while
// ...
} // main
- Java's standard libraries include a number of types of exceptions,
including
java.io.IOException
and
java.lang.NumberFormatException
.
- What should you do if you want to throw an exception, but you don't
care whether the caller catches it or not?
- Some would argue that this should never happen - all exceptions
should be caught.
- You are allowed to throw two things related to exceptions.
- Errors can not (or should not) be caught. They indicate
serious system errors.
- RuntimeExceptions can be caught, but need not be caught.
They seem to be included to accomodate programmers who have not
yet bought into (or learned about) Java's exception handling
mechanisms.
- At times, you'll want to throw exceptions from a method because your method
has encountered problems.
- In these cases, you'll need to
- Determine which kind of exception to throw (sometimes an existing kind
of exception; sometimes a new kind).
- Define any new types of exceptions you'll need.
- Determine an appropriate error message.
- Create and throw the the exception.
- Indicate that your method throws
- You can build and throw an exception with
throw new MyException(message);
- For example, suppose you wanted to ensure that the sender of a
message was non-empty. You might write:
public int readInt()
throws Exception
{
String str = this.readString();
if (!containsOnlyDigits(str))
throw new Exception("'" + str + "' is not a number");
// ...
} // readInt()
- You define your own exception classes with
public class MyException
extends Exception
{
} // class MyException
- You don't need to include anything in the body due to the wonders
of inheritance and polymorphism. This is enough to say that
it is possible to create and throw
MyException
.
- You may also want to create your own parameterized constructor.
public class MyException
extends Exception
{
public MyException(String msg) {
super(msg);
} // MyException(String)
} // class MyException
- This says ``When someone creates a
MyException
with
a String as a parameter, use that string as the parameter to the
constructor of Exception
(my superclass).''
- When you catch or throw an exception, you may be tempted to print
an error message. Don't
- Error messages should never be printed in utility methods.
- Instead, leave the error messages for the user interface.
- Example: Fraction and FractionTester. Suppose we create the
fraction 1/0. Who is responsible for yelling at the user?
Wednesday, 23 August 2000
- Created as a blank outline.
Thursday, 24 August 2000
- Slight reorganization to page design.
Wednesday, 13 September 2000
Back to Lab: Loops.
On to When Things Go Wrong.