Activities:
Lab Preparation
Download the provided zip file and unzip it. Create a new Eclipse project named Lab10. Add the given code to the project and link the external JAR jpt.jar to the project. You should have the following Java files:
Examples
that contains the test suite. It extends SimpleTestHarness.
SimpleTestHarness that
manages the test evaluation and reporting.
Interactions
that provides a framework for user interactions.Activity 1: Getting to Know the Java API
Go to the Java API at http://java.sun.com/j2se/1.4.2/docs/api/. Bookmark this page! When coding you will often use classes that are provided for you by Java. The Java API describes these classes and lists all of the fields and methods of these classes that are available to you.
The front page of the Java API lists all of the packages provided by Java. A package is a collection of related interfaces and classes.
Tips For Quickly Finding Class Specifications
The left frame of the API page lists all classes alphabetically. If you want the specifications for a specific class you can click in this frame and use your web browsers search function to find that class. For example, find the ArrayList class. Another way to quickly find Java API specifications is to search Google for "java api class x", where x is the name of the class you're searching for. For example, the search "java api class arraylist" returns the specifications for class ArrayList as the first result.
The Anatomy of a JavaDoc
All of the specifications are in a JavaDoc format. JavaDocs are automatically generated from source code based on specifically formated comments that the programmer adds for each class and each method. We won't cover the format of such comments here, but it's pretty easy to do yourself. For more details, see How to Write Doc Comments for the Javadoc Tool.
Lets use the ArrayList JavaDoc as an example.
The top of the JavaDoc lists the other classes that ArrayList extends and implements. In this case, ArrayList extends from the classes Object, AbstractCollection, AbstractList, and implements the interfaces Cloneable, Collection, List, RandomAccess, Serializable.
Next is a general description of the class. In this case, the JavaDoc says that ArrayList is a "Resizable-array implementation of the List interface."
Following this is a summary of fields, constructors, and methods provided by ArrayList. In general, classes will provide very few public fields and the JavaDoc will contain mostly specifications of methods. Look over some of the methods provided by ArrayList. We will be using a similar classes when cover the Java Collections framework in activity 3.
The method summaries provide headers (return type, name, and arguments) and a short description of the method's functionality. More detailed descriptions are linked from these summaries and appear farther down on the same page.
Activity 2: Using Exceptions
Exceptions provide a general method for dealing with errors that occur during the execution of a program. When an error occurs, an exception object is created. This exception can then be detected and handled smoothly, instead of causing the entire program to fail.
Catching Exceptions
Exceptions are either automatically created by Java when certain types of
errors occur or can be created manually by creating a new instance of an
exception class and throwing that exception.
As an example, consider the case of detecting when a divide by zero error
occurs. Look at the divide
method in the Interactions
class. This method takes two int's, x and y, and
returns x/y. What happens if y is 0? In this case, Java throws an ArithmeticException
that represents the error. We use a try-catch to handle the occurrence
of this error in a smooth way. The format of a try-catch is as follows:
try {
// some code that could result in an exception being thrown
} catch (ExceptionType1 e) {
// handle exceptions of Type1
} catch (ExceptionType2 e) {
// handle exceptions of Type2
}
There is one try-block, which contains code that can possibly create an exception. This is followed by one or more catch-blocks, each of which deals with a specific type of exception. In the case of the divide method there is only one type of exception we are interested in, so we have only one catch-block.
Try running the project and executing the divide method with different values for x and y. What happens when you enter 0 for y?
Manually
Creating and Throwing Exceptions
You can manually create and throw an exception when an abnormal situation occurs. In this case, what situations are abnormal are defined by the programmer. For example, we may only want to allow our program to work with int's less than 1000. See the multiply method in the Interactions class. This method takes two int's, x and y, and returns x*y. If x*y > 1000 an exception is created and immediately caught. Try running this method with various inputs and observe the results.
Defining a Method to Throw Exceptions
In the case of multiply, we created and immediately caught an exception. Sometimes we may not know how to immediately handle the exception and want to pass the exception back to where the method was called and handle the error there. We define methods to throw errors in the following way:
void foo(...) throws ExceptionType1, ExceptionType 2 {
// some code that can throw ExceptionType1 and ExceptionType2
}
Any method that calls foo should place that call of foo in a try-catch block to handle the error or should itself be declared to throw those exceptions to a higher level.
As an example, see multiplyAndThrow in Interactions. This method is similar to multiply but the exceptions are not immediately handled. Try running this method and causing an exception to be thrown. Notice that the exception is printed to the console in red. This signifies that the exception was never caught and was reported by Java as a fatal error.
The method multiplyAndCatch calls multiplyAndThrow and handles the exceptions that it can throw with a try-catch statement.
Exercise: Add the methods subtractAndThrow and subtractAndCatch to the Interactions class. These methods should be similar to subtractAndThrow and subtractAndCatch described above. Given two int's, x and y, they should return x-y and should produce an error if the result is negative.
Further
Activity 3: Using Collections
The Collection interface is the root of a hierarchy of interfaces that represent groups of objects. There are three main types of collections, each with a corresponding interface:
The LinkedList Class
Find the LinkedList class in the Java API. We will use this list class as the basis of two new classes, Stack and Queue. A basic definition of these classes is provided for you. Each of them has one field, list, which is a LinkedList. Use this list as the basis for the stack and queue. Specifically, look at the following methods in the LinkedList class: addFirst, addLast, getFirst, getLast, removeFirst, removeLast, and size.
Exercise:
Define Stack Methods
A stack is a last-in-first-out (LIFO) data structure. That is, the last element to be placed in the stack is the first one to be removed from it. An example is a stack of plates. Define the following four methods in the stack class. In the process of designing and implementing these methods you should define examples of stacks and test the methods. As an example, see the testStack method in the Examples class.
Methods to add to Stack:
Exercise: Define Queue Methods
A queue is a first-in-first-out (FIFO) data structure. The first element placed in the queue will the first one to be taken out. An example is a line at the bank.
Design, implement, and test the following methods for the Queue class:
Further Reading on Collections: Java tutorial on Collections
Challenge Problem: Defining a new Exception class
Defining
a new Exception Class
Define a new exception class named DivideException. You will want to look up the class ArithmeticException in the Javadocs to see what class you should be inheriting from.
Write a new method brokenDivide
Write a new method named brokenDivide(x,y). This method should raise an ArithemeticException if y = 0 and raises DivideException(x,y) if either of x or y are greater than 1000.
Write a new method fixedDivide
Write a new method fixedDivide(x,y) which calls brokenDivide(x,y), but handles exceptions so that DivideException is only passed on when the result is greater than 1000. Otherwise, return the correct result.