Download Exceptions - needham.k12.ma.us

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Exceptions
An exception is the occurrence of a detectable, abnormal situation that may lead to a system failure.
Example:
The following program fragment handles a very simple exception (division by 0) by sending a message to standard output:
double length, area;
System.out.println("Enter Length");
length = MyInput.readDouble();
System.out.println("Enter the area");
area =MyInput.readDouble();
if (length ==0)
System.out.println("Division by 0");
else
System.out.println("Width is "+(area/length));
This code is a simple fix for a simple runtime error. However, runtime errors come in all shapes, sizes and flavors, ranging
from “division by zero,” to “file not found,” to various I/O errors. To handle runtime errors uniformly and efficiently, Java
provides the try-throw-catch construction:
Example:
double length, area;
try
{
System.out.println("Enter Length");
length = MyInput.readDouble();
if (length == 0)
{
Exception e = new Exception("Division by zero");
throw e;
}
System.out.println("Enter the area");
area =MyInput.readDouble();
System.out.println("Width is "+(area/length));
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
System.out.println("All Done");
So what does this mean?
First of all, notice that most (not all) of the code is contained in two blocks: a try block and a catch block:
Try block
try
{
System.out.println("Enter Length");
length = MyInput.readDouble();
if (length == 0)
{
Exception e = new Exception("Division by zero");
throw e;
}
System.out.println("Enter the area");
area =MyInput.readDouble();
System.out.println("Width is "+(area/length));
}
Catch block
catch(Exception e)
{
System.out.println(e.getMessage());
}
Here is how the code works:
 If length equals 0 then
1. An object of class Exception is created and initialized with String “Division by zero.”
2. The object e is thrown (as a parameter) to the catch block.
3. Program control passes to the catch block. The remainder of the code in the
try block is skipped.
4. The program resumes with the code following the catch block.

If length is not equal to 0:
1. No Exception object is created.
2. The code in the catch block is skipped.
The idea is simple: if an exception occurs, an object encapsulating information about the exception is created and passed
(thrown) to a block of code that will handle the exception. In the example, the information contained in the object is the
string “Division by zero.”
In general, the try-throw-catch construction contains the following structures:

The try block:
try
{
code
throw statement
code
}

The throw statement:
A throw statement creates an object of the class Exception. This Exception object contains information
about the exception that has occurred. When an Exception object is thrown, the program branches to a
catch block. There may be more than one catch block. Every exception should be caught by some catch
block.

catch block:
catch(Exception e)
{
code
}
e is called the catch-block-parameter. Notice that e is an object of class Exception.
There are Exception subclasses e.g. IOException, FileNotFoundException. The Exception class is the
root class of all other exception classes.
After the code in the catch-block is executed the program continues with the code following the catch
block.

getMessage() Method:
Every Exception object contains a String attribute and a constructor with a String parameter:
new Exception(“Hi, I’m a string”);
The method getMessage() returns that string stored in the exception object:
e.getMessage()
Important:
Do not think that exception handling is just a fancy if-then-else statement.
A try-block can send a message to the catch-block, but an if-clause cannot
communicate with an else-clause.
Java Exception Hierarchy
Here is a partial view of the Exception class hierarchy. As you know, all classes extend Object. Under Object is the
Throwable class. Both Exception and Error extend Throwable. The Error class represents internal system errors (rare)
like Linkage errors. There is not much you can do about system errors.
Object
Throwable
Exception
ClassNotFound
Exception
IOException
ArithmeticException
RuntimeException
NullPointerException
Error
AWTException
IndexOutOfBounds
Exception
FileNotFound
Exception
System generated exceptions
Every exception does not necessitate a throw statement. If a standard exception occurs (file not found, array out
of bounds, IO exception, arithmetic exception, etc.) the system automatically throws the exception. Some system
exceptions (e.g., RunTime Exceptions) do not require handling but, as you will shortly see, other system
exceptions do.
Example:
int [] list = new int[5];
for (int i = 0;i < 5; i++)
list[i] = i*i;
for (int i = 0; i <= 5; i++)
System.out.println(list[i]);
You might have noticed that in the second for-loop the index of the array, list, will eventually go out of bounds. If
this fragment were to run within a program, the Java Virtual Machine would automatically throw an
IndexOutofBoundsException exception. Handling of this RuntimeException exception is not required. However,
because there is no catch block in the program to handle the exception, the final result is a rather inelegant crash.
0
1
4
9
16
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
at ArrayNoCatch.main(ArrayNoCatch.java:11)
Press any key to continue . . .
A more graceful scenario would have the program catch and handle the exception:
int [] list = new int[5];
try // notice a throw clause is not included
{
for (int i = 0;i < 5; i++)
list[i] = i*i;
for (int i = 0; i<= 5; i++)
System.out.println(list[i]);
}
catch (IndexOutOfBoundsException e)
{
System.out.println(“Array index out of bounds”);
System.out.println("Whoops");
}
The IndexOutOfBounds error is now handled by the catch block.
0
1
4
9
16
Array index out of bounds
Whoops
Press any key to continue . . .
The exception e in the catch block is of type IndexOutOfBoundsException, and because
IndexOutOfBoundsException is-a Exception, the code catch (Exception e), can be used in place of catch
(IndexOutOfBoundsException e). In other words, an IndexOutOfBoundsException object can be upcast to an
Exception object. Also, the catch block need not use the getMessage() method. Any exception handling
mechanism will do.
Example:
In the following segment, the system automatically throws a NullPointerException exception.
The string returned by getMessage() is simply null.
Square s = null; // Square is a valid class.
try
{
System.out.println(s.area());
}
catch(Exception e) // or catch (NullPointerException e)
{
System.out.println(e.getMessage());
}
System.out.println("All Done");
Output:
null
All Done
Since s is not instantiated, s is null. Thus s.area() causes a NullPointerException exception.
The Java Machine throws this exception automatically.
Example:
You might expect that the Java Virtual Machine throws some kind of arithmetic or division-by-zero error if the
variable length is set to 0.0 in the following fragment. However, that is not the case.
double length, width, area;
try
{
System.out.println("Enter Length");
length = MyInput.readDouble();
System.out.println("Enter the area");
area =MyInput.readDouble();
System.out.println("Width is "+(area/length)); //division by 0 ????
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
System.out.println("All Done");
The program produces the following output:
Enter Length
0.0
Enter the area
25.0
Width is Infinity
All Done
Recall that in Java, type double contains the value Infinity.
However, type int does not contain the value Infinity. If the data type in the previous example is changed to int, the
system will automatically throw an ArithmeticException exception. The exception should be caught.
int length, width, area;
try
{
System.out.println("Enter Length");
length = MyInput.readInt();
System.out.println("Enter the area");
area =MyInput.readInt();
System.out.println("Width is "+(area/length));
}
catch(ArithmeticException e)
{
System.out.println("Error: "+ e.getMessage());
}
System.out.println("All Done");
Example:
When accepting user input, a robust program should always check the validity of the input. If a user is
prompted for an integer, there is no guarantee that he/she will not accidentally type a character. If a user
enters invalid data, a program should handle the error and not crash.
The following code uses exception handling to check interactive input. Notice the use of the wrapper class
Integer. Input from the user arrives in the form of a String x. Then, x is passed to the parseInt() method. If x is
numeric, an integer value is returned; if not, the system throws a NumberFormatException exception.
boolean done= false;
while (!done)
{
try
{
System.out.print("Enter an integer: ");
x = MyInput.readString();
y = Integer.parseInt(x);
if (y==0)
done = true;
else
System.out.println("Square: " + (y*y));
}
catch (NumberFormatException e)
{
System.out.println("Illegal number: "+e.getMessage()+". Re-enter" );
}
}
Here is some sample output:
Enter an integer: 23
Square: 529
Enter an integer: aaa
Illegal number: aaa. Re-enter
Enter an integer: 18
Square: 324
Enter an integer: 23e
Illegal number: 23e. Re-enter
Enter an integer: 0
Multiple Catch Blocks
Several catch blocks can be associated with a single try block:
try
{
statements
}
catch ( ArithmeticException e)
{
statements
}
catch ( NullPointerException e)
{
statements
}
catch ( Exception e)
{
statements
}
In this case, the first catch block with parameter matching the type of thrown exception catches the exception.
Example:
The following fragment will print the square root of (non-negative) numbers. Exceptions occur when the user
enters a negative number or, possibly, a nonnumeric string.
String x = new String();
int y;
boolean done= false;
while (!done)
{
try
{
System.out.print("Enter an integer: ");
x = MyInput.readString();
y = Integer.parseInt(x);
if (y==0)
done = true;
else if (y < 0)
throw new Exception("Negative Number. Re-enter");
else
System.out.println("Square root: " + (Math.sqrt(y)));
}
catch (NumberFormatException e)
{
System.out.println("Illegal number: "+ e.getMessage() +". Re-enter" );
}
catch (Exception e)
{
System.out.println( e.getMessage());
}
}
If a user enters abcd as input, the Java Machine will throw a NumberFormatException exception when the
parseInteger method is called. The first catch block will catch the exception.
On the other hand, if the user input is –54, the statement
if (y < 0)
throw new Exception("Negative Number. Re-enter");
will cause an exception (type Exception) to be thrown.
The first catch block will not catch this exception since the parameter is of type NumberFormatException.
However, the second catch block with parameter type Exception will catch the exception. (Note that the
Math.sqrt(double x) method will not throw an exception if x is negative. Instead, the function returns the value
NaN (Not a Number).
Sample output:
Enter an integer: 4
Square root: 2.0
Enter an integer: -4
Negative Number. Re-enter
Enter an integer: ee
Illegal number: ee. Re-enter
Enter an integer: 0
Example
The following fragment (which does nothing!) has several catch blocks corresponding to various types of
exceptions including a contrived exception which occurs if user input is greater than ten.
No throw statement is necessary for an ArithmeticException or an IndexOutOfBound exception. The system
automatically throws those exceptions if any occur.
try
{
int a, b, c;
int [] s = new int[3];
System.out.println("Enter two numbers a, b");
a= MyInput.readInt();
b= MyInput.readInt();
if (a>10 || b > 10 )
throw new Exception("number is greater than 10");
c = a/b; //possible division by 0
s[c] = a; // possible index out of bounds
System.out.println(a+ " " +b+ " " +c+ " " +s[c]);
}
catch ( ArithmeticException e)
{
System.out.print (e.getMessage());
System.out.println(" Arithmetic exception");
}
catch ( IndexOutOfBoundsException e)
{
System.out.print (e.getMessage());
System.out.println(" Array exception");
}
catch ( Exception e)
{
System.out.println(e.getMessage());
}
Unchecked Exceptions
Runtime exceptions and Error exceptions (see the hierarchy above) fall into the category of unchecked exceptions.
Unchecked exceptions, like division by zero or an array index out of bounds, can occur anywhere in any method.
An unchecked exception is the most common type of exception. The table below enumerates some of the more
common unchecked exceptions. There are many more.
Some Common Unchecked Runtime Exceptions
ArithmeticException
ArrayIndexOutOfBoundsException
ArrayStoreException
ClassCastException
IllegalArgumentException
NullPointerException
NumberFormatException
StringIndexOutOfBounds
Some arithmetic error e.g. division by zero.
Invalid index value for an array.
Invalid type for an array element.
Invalid cast.
Invalid argument when calling a method.
Attempt to dereference a null pointer.
Invalid string in a conversion to a number.
Invalid index value for a String.
As previously mentioned, you can either ignore unchecked exceptions or handle them. The following code
segment causes the system to throw an IndexOutOfBoundsException exception. The code completely ignores the
possibility of an exception.
int [] list = new int[5];
for (int i = 0;i < 5; i++)
list[i] = i * i;
for (int i = 0; i<= 50; i++)
System.out.println(list[i]);
When embedded in a program, the rather inelegant output is:
0
1
4
9
16
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
at ArrayCatch.main(ArrayCatch.java:17)
Moreover, if a method explicitly throws an unchecked exception, it is not necessary to handle
the exception. An explicit throw statement appears in the code below but no handling
mechanism is present.
int [] list = new int[5];
for (int i = 0;i < 5; i++)
list[i] = i*i;
for (int i = 0; i<= 50; i++)
if (i >= 5)
throw new IndexOutOfBoundsException("Oops! Out of Bounds");
else
System.out.println(list[i]);
Notice the "Oops! Out of Bounds" message appears in the program output, that is when the program crashes:
0
1
4
9
16
Exception in thread "main" java.lang.IndexOutOfBoundsException: Oops! Out of Bounds
at ArrayCatch.main(ArrayCatch.java:15)
The Throws Clause
An exception that is not unchecked is called a checked exception. If a checked exception is thrown in a method,
the method must either:
 catch (try-catch construction) the exception or
 list the exception in a throws clause appended to the method signature.
A throws clause enumerates the type of exceptions a method may throw. If a method does not catch a checked
exception, the exception object is passed to the caller. The caller must either handle the exception or list the
exception in a throws clause. Checked exceptions can be passed along the chain of method calls right up to the
main method and finally to the system.
Example:
The class Square below has no exception handling mechanism. Any value, positive, zero, or negative, is an
acceptable value for the variable side.
public class Square
{
int side;
public Square()
{
side = 1;
}
public void setSide(int x)
{
side = x;
}
public int area()
{
return side * side;
}
}
public class TestSquare
{
public static void main(String[] args)
{
int side;
Square s = new Square();
System.out.println("Enter side");
side = MyInput.readInt();
s.setSide(side);
System.out.println("Area:"+ s.area());
}
}
The next implementation of Square throws and catches an exception just in case side is not positive. Everything is
handled in setSide().
public class Square
{
int side;
public Square()
{
side = 1;
}
public void setSide(int x)
{
try
{
if (x <= 0)
throw new Exception("Side must be positive");
else
side = x;
}
catch (Exception e)
{
System.out.println(e.getMessage());
System.exit(0);
}
}
public int area()
{
return side*side;
}
}
Sample Run:
Enter side
-8
Side must be positive
Press any key to continue . .
In this next implementation of Square, method setSide throws an exception if side is not positive. However, the
exception is not handled with a try-catch structure. Instead, a throws clause is added to the method signature. If
an exception occurs, the exception is passed to the caller. Look closely at the code. It does not compile.
public class Square
{
int side;
public Square()
{
side = 1;
}
public void setSide(int x) throws Exception
{
if (x <= 0)
throw new Exception("Side must be positive");
else
side = x;
}
public int area()
{
return side*side;
}
}
public class Tester
{
public static void main(String[] args)
{
int side;
Square s = new Square();
System.out.println("Enter side");
side = MyInput.readInt();
s.setSide(side);
System.out.println("Area:"+
s.area());
}
}
Compilation of the Square class causes no problem. The method setSide throws an exception and contains a
throws clause. Square has fulfilled its contract. However, an attempt to compile Tester.java results in the following
error message:
C:\Java Applications\Tester.java:11: unreported exception java.lang.Exception; must be caught
or declared to be thrown
s.setSide(side);
^
1 error
When an exception is thrown in setSide(), the exception is passed to the caller main(). The compilation error
occurred because method main() neither handled the exception nor included a throws clause for the exception,
even though main() was responsible for the exception. Two remedies are detailed below.
main() handles the exception
public class Tester
{
public static void main(String[] args)
{
int side;
Square s = new Square();
System.out.println("Enter side");
side = MyInput.readInt();
try
{
s.setSide(side);
System.out.println("Area:"+ s.area());
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
}
}
main() includes a throw clause
public class Tester
{
public static void main(String[] args)
throws Exception
{
int side;
Square s = new Square();
System.out.println("Enter side");
side = MyInput.readInt();
s.setSide(side);
System.out.println("Area:"+ s.area());
}
}
//The exception handled by the program:
//The exception passed to the Java Virtual
Machine:
Output:
Output:
Enter side
-4
Exception in thread "main" java.lang.Exception:
Side must be positive
at Square.setSide(Square.java:13)
at Tester.main(Ex2.java:12)
Enter side
-4
Side must be positive
Creating an Exception class:
You can create your own exception class by extending Exception. The following example creates a class
DivisionByZero. Notice the calls to the super class (Exception) in the two constructors.
Example
public class DivisionByZero extends Exception
{
//constructors
public DivisionByZero()
{
super("You have attempted a division by zero");
}
public DivisionByZero(String s)
{
super(s);
}
}
public class DivisionByZeroTest
{
public static void main(String args[])
{
double length, area;
try
{
System.out.println("Enter Length");
length = MyInput.readDouble();
if (length == 0)
throw new DivisionByZero("Division by zero exception");
System.out.println("Enter the area");
area =MyInput.readDouble();
System.out.println("Width is "+(area/length));
}
catch(DivisionByZero e)
{
System.out.println(e.getMessage());
}
System.out.println("All Done");
}
}