Return to lecture notes index

15-100 Lecture 17 (Wednesday, October 11, 2006)

Today's Quiz

  
/*
 * 1. Make this class Comparable
 * 2. Write the standard method, the standard way,
 *    to determine the equivalence of two Boxes.
 */
 
class Box implements Comparable {

  private double heightInches;
  private double widthInches;
  private double lengthInches;
  
  ...
  
  /*
   * Write the standard method to determine if two boxes are equivalent
   * Boxes are equivlaent if, and only if, they have exactly the 
   * same dimensions.  
   */
   
   public boolean equals (Object o) {
     Box b = (Box) o;
     
     if (heightInches != b.heihgtInches)
       return false;
       
     if (widthInches != b.widthInches)
       return false;
    
     if (lengthInches != b.lengthInches)
       return false;
       
     return true;
   
   }
   
  /* 
   * Write the standard method to compare to boxes, sorting them
   * by VOLUME (length * width * height)
   */
   
   public int compareTo (Object o) {
   
     Box b = (Box) o;
     
     double difference = (int)((lengthInches*widthInches*heightInches) - 
                           (b.lengthInches*b.widthInches*b.heightInches) );
   
     if (difference == 0.0)
       return 0;
       
     if (difference > 0.0)
       return 1;
       
     return -1;
   
   }
   
}


  

Exceptional Control Flow

Let's think about the normal process involved when two object communicate. One object sends another object a message. That occurs by a method invocation. Then, after exhibiting some behavior, the receiving object replies. It does that by returning from the method call, and possibly by returning a value.

But, what happens when something out of the ordinary happens? For example, what happens if the method encounters an error and can't perform the requested actions? In C or Pascal, this is typically handled by using some special return value.

For example, in C, the convention is that all functions return "int" values. A return value of 0 indicates that the function completed successfully. Each negative return value generally indicates a different error. And, each positive return value generally indicates a non-error condition that prevented the function from completing. Since the return values are used to indicated the return type, values that are returned are generally managed as parameter's using C's "pass by address" mechanism.

But, this type of undocumented hackery is not necessary in C++ or Java. These languages support an "exception mechanism" that can be used to handle errors and other exception conditions -- both within a message and to communicate unhandled errors up the call chain.

As you'll learn today, Java's exception mechanism is far superior to the approach used by C, Pascal, and others. It can be used to remove error handling from the body of code, making the algorithmic component much cleaner. It is also much more self-documenting, because each type of error is represented by a meaningfully named class, not by a number. And, since it provides a different mechanism for returning in the exceptional case than the normal case, return values can be just that. All in all, it makes code more logical and more readable.

Representing an Error (Or Other Exceptional Condition)

In Java, errors or other exceptional conditions are represented with instances of the Exception class. An Exception is a reasonably simple class. For our purposes it has a two constructors, one of which take as String message, and one of which is the default constructor, which takes no parameters.

When an exception event, a.k.a, exception, occurs, the code that detects it creates a new Exception to represent the problem. When calling the constructor, it generally sets detailed information about the situation in plain-language, by passing it as the "message" to the constructor. When an Exception is converted to a String using toString(), it is this message that becomes part of the returned String.

Types of Exceptions

As we discussed moments ago, when errors or conditions were returned from C or Pascal functions, this return often took the form of a negative return value, with a different return value for each condition. The calling function would simply use a collection of if statements, or a switch/case statement to demultiplex the error conditions and take appropriate action to sort out the return value and take appropriate action. But, so far, in Java, we've only discussed one type of Exception. How are different conditions represented?

Java represents different types of Exceptions using inheritence. In Java, the generic Exception class can be extended to form different types of Exceptions. In fact, even the derived types are often extended to create even more specific types of exceptions.

Just to show an example, here is a very small piece of the Exception inheritence tree:

Creating Your Own Exceptions

You can create your own Exceptions, just by extending the Exception class. For example, let's consider the menu we wrote earlier this semester. What happens if the user makes a wrong choice? Retries too many times? Let's create Exceptions to model these situations.

  class MenuException extends Exception
  {
    public MenuException (String message)
    {
      super (message);
    }
  }
  

You probably haven't seen it before, but "super()" invokes the constructor of the super, a.k.a., parent class. In other words, the constructor for SetException will take a message as a String parameter and pass it to the constructor of the Exception class. Our function is now an Exception and handles a message exactly as does the generic type -- but, since we have a new type of extension, we will be able to tell what type of situation is present.