Exceptions

advertisement
ENIC4023 - Networked Embedded System Development
Exceptions Lab
Overview of Java Exceptions
Java provides a standard mechanism for dealing with errors: exception handling. This is a means to deal with
unusual conditions that can arise during execution and provides for dealing with these conditions in a consistent
way.
Java has a class called Throwable, from which two other major classes, Error and Exception, inherit.
Normally Throwable is not used directly but you do have to have a class that is a subclass of Throwable to
throw an error or an exception. All Throwable objects contain information on the exception stack for the
executing thread at the time the error or exception object was created. Normally you won't write code to deal
with Error or any subclass of it; an Error stems from events like device failures or out-of-memory
conditions.
Throwable
Error
Exception
RunTimeException
Other Exceptions
There are many subclasses of Exception. Of these RunTimeExceptions are not normally dealt with in
your code. Such exceptions probably represent a program bug, eg if your code tries to access an array element
that does not exist, such as the 6th element of a 5-element array object, this would cause an
ArrayIndexOutOfBoundsException. Another example that would generate a RunTimeException is
trying to use an object before it is instantiated. RunTimeExceptions represent problems in your code, you
should not try to catch them, but rather resolve the problems in your code.
There are many Exception subclasses that do not represent RunTimExceptions, but are generated by
other conditions in a program. Java requires that you deal with these, often these are exceptions that a developer
has decided that their code needed to throw under given circumstances. Such an exception might not represent a
bug or logic problem, but rather it might merely be an anomalous condition that you might want to try to deal
with in your code. Even if you do not want to deal with the condition, the Java compiler won't let you not do
something about a thrown Exception. Java has a rule: its the "handle or declare rule". At compile time, the
compiler verifies that all checked exceptions are handled or declared in your code, at runtime the Java Virtual
Machine implements your choice.
Thus you either need to deal with a potential Exception, or tell Java to pass the Exception up the call
stack to your method's caller. Java will continue up the call stack looking for some method that will deal with
the exception. If it runs out of methods, the Exception is handled by the Java runtime by interrupting
execution and displaying the exception on System.err.
Handling Exceptions
The mechanism Java has for dealing with Exceptions is the try-catch-finally construct. The basic syntax is:
try {
//put code that might throw
//an Exception inside a try block
} catch(<SomeExceptionClass> excpObjRef) {
//name a specific exception class and object reference
//put code here to deal with the
//Exception type if it is thrown
} finally {
//a finally block is optional
//if present it is always executed, use it to
//do something that needs to be done no matter what
}
Where a method that you call may throw an Exception (or subclass of Exception), you call it inside a
try block (or clause). The best way to know if a method can throw an Exception is to check the API
documentation. If it can, it will say:
someMethod(<parameters>) throws SomeExceptionClass, someOther..., ...
If the signature of the method or constructor says throws someException, it falls under the "handle or
declare" rule. If the exception is to be handled, the method or constructor call should be inside a try block. One
or more catch blocks should contain the code to handle the exception(s) and followed optionally with a
finally block. For one try block you can have essentially any number of catch blocks. Java processes
catch blocks by examining the type of Exception class listed in the catch block parameter list. The first
catch block whose Exception type matches, or is a superclass of the type of Exception thrown from the
try block is executed.
Example - Using try ... catch ... finally
The Integer class wraps a value of the primitive type int in an object. An object of type Integer contains a
single field whose type is int. In addition, this class provides several methods for converting an int to a String
and a String to an int, as well as other constants and methods useful when dealing with an int. See the Java API
documentation for details. The Integer class has a constructor as shown:
public Integer(String s) throws NumberFormatException
Thus if the String is of numeric integer format the Integer object will be created, otherwise a
NumberFormatException will be thrown. The following application uses this to determine if a command line
argument is an integer or not:
public class ExDem1 {
public static void main(String[] arg) {
try {
Integer num = new Integer(arg[0]);
System.out.println(num.intValue() + " is an integer");
} catch (NumberFormatException e) {
System.out.println(arg[0] + " is not an integer");
} finally {
System.out.println("No matter what, have a nice day!");
}
}
}
In the try block a new Integer object is created with the value of the command line argument. If this is
successful a message is output to say the value is an integer. If an exception occurs during the creation of the
Integer object the remainder of the try block is not executed; instead the appropriate catch clause is. Here the
only exception that can be thrown is the NumberFormatException, so there is a catch block for it. If more than
one exception could have been thrown there could be multiple catch clauses to handle each, or a catch block for
a superclass of the exception classes could be used to handle them all. The finally block is always executed no
matter whether an exception occurred at all, so the "have a nice day" message will always be output.
Try running the above application without a command line argument. An ArrayIndexOutOfBoundsException
occurs. As there is no catch clause for this exception it is handled by the java run-time environment in a way
that would not be friendly to users of this application. A way of stopping this problem occurring was shown in
the Console Applications lab. This involved checking the size of the arg array before accessing it. An alternative
here would be to catch the exception; the small addition to the above code to do this is left as an exercise.
Example - Throwing an Exception
As well as catching exceptions, your code can throw them as well. Throwing an exception is done with the
throw keyword. This exception must either be handled or declared in the signature of the method within which
it can occur. Consider extending the above example to throw and catch an exception if the number entered is
odd.
public class ExDem2 {
public static void main(String[] arg) {
try {
Integer num = new Integer(arg[0]);
if ((num.intValue() % 2) != 0) throw new ArithmeticException();
System.out.println("number is even");
} catch (NumberFormatException e) {
System.out.println("only integers allowed");
} catch (ArithmeticException e) {
System.out.println("number is odd");
} finally {
System.out.println("No matter what, have a nice day!");
}
}
}
Example - Creating Your Own Exception Class
You can also create your own exception subclass by extending the Exception class. Exception subclasses need
to provide some common elements. There needs to be a String to store the reason for the exception. Also, there
needs to be a constructor for the exception, which accepts a String to put into the reason data member. The
getMessage() method may optionally be coded to return the reason for the exception together with other
desired information; alternatively the inherited version of getMessage() may be used.
The following shows an OddException class to handle an exception when a number is odd (instead of using the
more general ArithmeticException):
public class OddException extends Exception {
String message = "";
public OddException(String reason) {
message = reason;
}
public String getMessage() {
return message;
}
}
The application code that uses it is:
public class ExDem3 {
public static void main(String[] arg) {
try {
Integer num = new Integer(arg[0]);
if ((num.intValue() % 2) != 0) throw new OddException(arg[0]);
System.out.println("number is even");
} catch (NumberFormatException e) {
System.out.println("NumberFormatException: " + e.getMessage());
System.out.println("only integers allowed");
} catch (OddException e) {
System.out.println("OddException: " + e.getMessage());
System.out.println("number is odd");
} finally {
System.out.println("No matter what, have a nice day!");
}
}
}
Example - A Queue Class Revisited
The Queue class example in the OOPs lab 1 had no way of indicating when the queue was empty or full, hence
anomalous conditions could occur when trying to add to a full queue or trying to remove from an empty queue.
Having the Queue class throw an exception is one way of handling these situations (though not the only way).
The Queue class from the OOPs lab 1 is modified as shown:
public class Queue {
private
private
private
private
private
private
final int QSIZE = 5;
String[] store = new String[QSIZE];
int inLocation = 0;
int outLocation = 0;
boolean empty = true;
boolean full = false;
public void enter(String name) throws QueueException {
if (full == true) {
throw new QueueException("queue full");
} else {
inLocation++;
inLocation %= QSIZE;
empty = false;
store[inLocation] = name;
if (inLocation == outLocation) {
full = true;
}
}
}
public String leave() throws QueueException {
if (empty == true) {
throw new QueueException("queue empty");
} else {
outLocation++;
outLocation %= QSIZE;
full = false;
if (inLocation == outLocation) {
empty = true;
}
return store[outLocation];
}
}
}
Two private attributes, each of type boolean are added to store the status of the queue. Where the queue is
neither empty or full, both flags will be false. If as a result of an item being entered on the queue, the queue
becomes full (as indicated by the in and out indice attributes for the array being equal), the full attribute is set
to true. If as a result of an item being removed from the queue, the queue becomes empty (as also indicated by
the in and out indice attributes for the array being equal), the empty attribute is set to true.
The situation where the queue is full and the enter method is called can now be dealt with; here by throwing a
QueueException. Similarly for the situation where the queue is empty and the leave method is called. The
QueueException is a programmer defined exception class as shown:
public class QueueException extends Exception {
String message = "queue error";
public QueueException(String reason) {
message = reason;
}
public String getMessage() {
return message;
}
}
When the exception is thrown, a new object of the QueueException class is created. This has a string to store the
reason for the exception and a constructor that initialises the string.
An application that demonstrates the use of the new Queue class follows:
public class QueueDemo {
public static void main(String[] arg) {
Queue bank = new Queue();
try {
bank.enter("Wally");
System.out.println("Wally into bank");
bank.enter("Florence");
System.out.println("Florence into bank");
bank.enter("Snorky");
System.out.println("Snorky into bank");
bank.enter("Dilbert");
System.out.println("Dilbert into bank");
bank.enter("Ermitrude");
System.out.println("Ermitrude into bank");
bank.enter("Musky");
System.out.println("Musky into bank");
} catch (QueueException qe) {
System.out.println(qe.getMessage());
}
try {
System.out.println(bank.leave() + " out of
System.out.println(bank.leave() + " out of
System.out.println(bank.leave() + " out of
System.out.println(bank.leave() + " out of
System.out.println(bank.leave() + " out of
System.out.println(bank.leave() + " out of
} catch (QueueException qe) {
System.out.println(qe.getMessage());
}
}
bank");
bank");
bank");
bank");
bank");
bank");
}
A Queue object is created but this has a maximum size of 5 items. An attempt is made to put 6 items into the
queue. The first 5 will go on OK but then an exception will be thrown by the Queue object. A method that can
potentially throw an exception must be called from within a try block; the corresponding catch block here will
just output the exception message to the screen.
Similarly, it is then tried to remove 6 items from a (full) queue of 5, and again an exception will be thrown by
the Queue object.
Check out the above example by running it for yourself by ....
(1)
(2)
(3)
(4)
(5)
(6)
(7)
(8)
Create a new subdirectory to store the files in.
Use a text editor to enter the above three classes in separate files (Queue.java, QueueException.java,
QueueDemo.java).
Open a command prompt and navigate to your subdirectory.
Compile the QueueException class with: javac QueueException.java
Compile the Queue class with: javac Queue.java
Compile the QueueDemo class with: javac QueueDemo.java
Run the whole application with: java QueueDemo
Experiment with the code!
Download