Lecture 20, OOP, Exceptions

Reading

Java Precisely: 9.5, 9.8, 12.6.5, 12.6.6, 15.

Slide handout for lecture 8.

Optional: The java tutorial: Handling Errors with Exceptions (its a nice easy read).

Study Guide

There are two issues for this lecture. First, how should one write programs which use exceptions. This will be covered in the slides, but also exercise 3 below is important. In particular it is important to understand the two programmer roles involved in exceptions. Second, we will look at the efficiency issues. This is a minor point, but useful to know.

In 9.5 there is inheritance rule for the throws clause in method heads.

In 9.8 there is just a few lines at the end about which exceptions a method can throw.

12.6.5 is about the throw statement, and 12.6.6 is about the try-catch-finally statement. The try-catch-finally statement can also be explored using example 74. See the Java Precisely homepage to get the source code for the example.

Section 15 is about the checked and unchecked exceptions. 

Exercises

Exercise 1

The goal of this exercise is to examine the difference between checked and unchecked exceptions. Try to understand it as presented by Bertrand Meyer, and summarized in the slides (the contracts, pre- and post- conditions). Sometimes the Java libraries are in accordance with those guidelines, sometimes they are not. I have not been able to find other advice which is consistent throughout the Java libraries.

The method void sort( List ) in the class Collections (from package java.util) is noted in the API documentation to throw two kinds of exceptions.

  1. Are they checked or unchecked?
  2. What might be the rationale for that design?
  3. Are the exceptions satisfying the principle of "fit level of abstraction" from the slides.
  4. Can the sort method throw other exceptions than the two noted in the API documentation?
  5. Should you, based on the above, always place a call to sort in a try - catch construction?

Exercise 2

  1. Draw a diagram of the call stack in a similar fashion as in the slides of the code given below. If you get completely stuck, you can cheat a bit and execute the program to see what happens. You do not need to make a new diagram for every method call. Several stack-growths can be put into one diagram, while the raising of an exception (and reduction of the stack) calls for a new diagram or when entering a different block of a try-catch-finally construct...4-5 diagrams should suffice.

    class TryCatchExample{
    	static class ExceptionA extends Exception {
    		int n;
    		ExceptionA(int n){this.n = n;}
    		public String toString(){return "A: " + n;}
    	}
    	static class ExceptionB extends Exception {
    		int n;
    		ExceptionB(int n){this.n = n;}
    		public String toString(){return "B: " + n;}
    	}
    	static class ExceptionC extends ExceptionA{
    		ExceptionC(int n){super(n);};
    		public String toString(){return "C: " + n;}
    	}
    
    	void pip(int i) throws ExceptionA{
    		if (i>4)
    			throw new ExceptionA(i);
    		else
    			throw new ExceptionC(i);
    	}
    
    	int pap(int i) throws ExceptionB {
    		if (i<0)
    			throw new ExceptionB(i);
    		else
    			try{ // try block 2
    				pip(i);
    				return 7;
    			}
    			catch(ExceptionC ec){
    				try{ // try block 3
    					return pap(i-2);
    				}
    				catch(ExceptionB eb){
    					return eb.n;
    				}
    				finally{
    					System.out.println("Finally inner pap");
    				}
    			}
    			catch(ExceptionA ea){
    				throw new ExceptionB(i);
    			}
    			finally{
    				System.out.println("Finally outer pap");
    			}
    	}
    
    	public static void main(String[] a){
    		try{ // try block 1
    			System.out.println("pap returned: " + new TryCatchExample().pap(1) );
    		}
    		catch(ExceptionB eb){
    			System.out.println("pap failed:" + eb);
    		}
    	}
    }
    

  2. Why is it wrong to change the order of the catch blocks in the pap() method like the code below?
  3. class C {
     	int pap(int i) throws ExceptionB {
    		if (i<0)
    			throw new ExceptionB(i);
    		else
    			try{ // try block 2
    				pip(i);
    				return 7;
    			}
    			catch(ExceptionA ea){
    				throw new ExceptionB(i);
    			}
    			catch(ExceptionC ec){
    				try{//try block 3
    					return pap(i-2);
    				}
    				catch(ExceptionB eb){
    					return eb.n;
    				}
    	}		}
    



Exercise 3

The goal of this exercise is to let you develop your own class which can throw exceptions. And to let you examine the design issue involved in the two roles of the programmer, though you will shift back and forth between the two roles. An other purpose is to have an exercise which uses interfaces.

This exercise is about Calendar dates. A Date object is characterized by the following interface:

interface Date {

	class DateException extends Exception{
		DateException(String errorMessage){
			super(errorMessage);
		}
	}

	void setDate(int year, int month, int day) throws DateException;
	int getYear();
	int getMonth();
	int getDay();
}

Notice, it is legal for an interface to declare a local class. Therefore the DateException class can be declared as a local class, and therefore be available to all classes which implement the interface.

  1. Create a class MyDate which implements the interface. The class should have three private integer fields which represents year, month, and day. There should be a constructor which takes three parameters, a year, a month and a day, but internally it must use the method setDate(...). You should ignore leap years! Assume there is 28 days in February. You must determine how the checked exception DateException should be handled in the constructor.
  2. The class DateDialog (See Code on the net) has a method editDate(Date d), which brings up a window in which one can edit the Date given as parameter. The dialog consists of three small text fields that is used for editing the year, month and date. Also there is a larger text area which can be used to write messages to (error messages perhaps:-). Finally, the accept button attempts to store the date using the storeDate method.
    1. We have created a main method, which creates an instance of the MyDate from 1), and passes it as parameter to the editDate method(). What does editDate return if you press the cancel button.
    2. Change the error handling in the storeDate method so that a precise error message is given if something different from an int is written in one of the input field - the message should state which field is wrong. 
    3. (optional)Next we want to give appropriate error messages if one specify a date which is wrong, for instance May 37th 2004. To do this, it is necessary to change the DateException so it can remember which field is in error. Change the DateException in Date to the following:
      	class DateException extends Exception{
      		public final String field;
      		// remember the field so we can ask.
      		public DateException(String field){
      			super("Date is wrong in " + field);
      			this.field = field;
      		}
      	}
      and its usage in MyDate. The purpose of these changes are that you can change the catch in the storeDate method in DateDialog can give a precise error message. Hand in the new version of MyDate, and the new version of storeDate.

If you want to work with dates which handle leap years, check out class java.util.Calendar and its subclass GregorianCalendar.