Aston University Birmingham B4 7ET http://webct.aston.ac.uk/ JPD: Lab 7 Ian T. Nabney Module CS1410 March 30, 2007 1 Introduction In this lab session you will improve your understanding of Java error handling mechanisms, including exceptions and assertions. All material needed for the lab can be found on WebCT. At the end of this lab class you should be able to: • use assertions to test assumptions about a program; • throw exceptions where errors occur; • write client code that handles exceptions appropriately; • write exception classes. The lab class is mainly based on the address book project that is covered in Chapter 12 of the BlueJ book. There will be a short on-line quiz during the lab session worth 3% of the total marks for the module. 2 Understanding the System We shall work with a GUI-based version of the system. Avert your eyes from the design: the parsing and execution of commands follows the same structure as the original Game-of-Zuul. 1. Download the software from WebCT. Run the system: the main method is contained in the AddressBookDemo class. You will see that there are three tabs, each of which represents an action that can be performed on the system: Search the Entries; Enter New Details; List the Entries. (The text-based version of the system also allows the user to delete entries). 2. Start with the List tab. Use the List button to see the (rather boring) list of entries that have been set up for you. 3. Now try the “Enter New Details” tab. Add a new entry for the name “richard” (and any phone number/address that you wish). Run the list command to check that it has been entered correctly. Copyright (c) Aston University 2005–7 2 CS1410 JPD: Lab 7 4. Finally use the “Search” tab. Type the letter “r” in the text field at the top of the pane. You should see two entries appear: one for “richard” and one for “ruth”. When you continue by typing “i”, the entry for “ruth” disappears. What happens when you delete the “i” again? 5. Experiment with retrieving details by phone number. 3 Handling Errors In this section we will look at the different sorts of error that can arise and show how to program effective ways of dealing with them. 1. Look at the removeDetails method in AddressBook public void removeDetails(String key) { if(keyInUse(key)) { ContactDetails details = book.get(key); book.remove(details.getName()); book.remove(details.getPhone()); numberOfEntries--; } } When the wrong details (for example, a null string) are entered no error message is displayed. Do you think an AddressBook should print an error message whenever it receives a bad argument to one of its methods? Are there any situations where a printed error message would be inappropriate? 2. Review all of the methods of the AddressBook class and decide whether any of them should throw an IllegalArgumentException. (Hint: look to see where there is an if-statement testing method arguments.) If so, add the necessary checks and throw statements. Use a Scrapbook page to call the methods directly and test that the appropriate exceptions are thrown. Recall that you can create a Scrapbook page from File:New:Other:Java:Java Run/Debug. Execute code on the page by selecting it and then choosing Execute from the Run menu (or contrl-U as the shortcut). You could create an (empty) AddressBook object and two ContactDetails objects with the same name or phone number and check that an exception is thrown when the second set of contact details is added to the address book. 3. Add appropriate javadoc comments to describe any exceptions thrown by methods in the AddressBook class. Copyright (c) Aston University 2005–7 CS1410 JPD: Lab 7 3 4. Using the GUI, list the entries in the contact list. Now try to add a new contact with blanks for all the details. What happens when you list the entries? Do you notice any change? 5. The class that needs modification is ContactDetails. Add some code to the end of the con- structor so that if both the name and the phone number are blank (have zero length) then an IllegalStateException is thrown. Now try adding a contact with blanks for all the details. What is the behaviour of the system? Is this user-friendly? 6. It has been decided to create a new checked exception DuplicateKeyException. This should be thrown by the addDetails method if either of the non-blank key fields of its argument is already currently in use. The exception class should store details of the first offending key. Write the new class. Which exception class should it be a subclass of? 7. Modify the signature of addDetails to show that it throws DuplicateKeyException. Are there any other methods that need an additional throws specification? 8. Now we must modify the client code so that it handles the exceptions properly. Checked excep- tions must be caught (or declared as thrown). We shall start with the AddressBookDemo class. The constructor calls addDetails, and the relevant part of the method should be surrounded by a try-catch block. As this is setting up the database, the catch block can’t really repair the error, so should just print an error message on the console and terminate the application using System.exit(1) (a non-zero argument to System.exit denotes abnormal termination). 9. The GUI also needs to handle errors. For most errors it is sufficient to provide a simple error message to the user and allow the application to continue. We need to add a try-catch block to the actionPerformed method in the ActionListener attached to the add button. add.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ev) { try { book.addDetails( new ContactDetails(nameField.getText(), phoneField.getText(), address.getText())); } catch (IllegalArgumentException e) { reportException(e);} } }); The private method reportException has been written for you. It puts up a message dialog box (see JOptionPane) that prints out the error message contained in the exception object. 10. Now to deal with the other type of exception: the DuplicateKeyException. This is raised by the addDetails method, and so the catch block should also be in the block of code given above. Copyright (c) Aston University 2005–7 4 CS1410 JPD: Lab 7 However, we will make the handler for this different. If there is a duplicate key, then it makes sense to offer the user the chance to overwrite the old information with the new information for the duplicate key. Call a helper method offerChange with the exception object and the new contact details (as variables from the try block are not available in the catch block, you will have to create a ContactDetails object in the catch block; do so with the same arguments as in the try block). try { book.addDetails( new ContactDetails(nameField.getText(), phoneField.getText(), address.getText())); } catch (DuplicateKeyException e) { offerChange(e, new ContactDetails(nameField.getText(), phoneField.getText(), address.getText())); } catch (RuntimeException e) { reportException(e);} The second catch block guards against the contact details being invalid (e.g. blank fields). 11. Now write the offerChange method. It should display a confirmation dialog (see the API for the Java class JOptionPane) as in Figure 1(b) with a message asking if the user wants to overwrite the details for the duplicate key (which can be obtained from the exception object). If the user selects “Yes”, then the changeDetails method should be called. (You will also need to put this in a try-catch block: however, the catch block can be empty, since we can be sure that no error can be raised since we know that the key is in the database.) if (response == JOptionPane.YES_OPTION) { try { book.changeDetails(e.getKey(), details); } catch (Exception e2) { } } 12. Now run and test this code. First, add a new entry with empty name and phone number You should see a message dialog as in Figure 1(a). Then add an entry with a key (either name or phone number) that is already in the database. You should get a confirmation box as in Figure 1(b). If you do decide to overwrite the details, then this should be reflected in the database: use the List panel to check on this. 4 Assertions While exceptions are a good mechanism for checking the preconditions of a method (such as the argument validity), assertions are a good way of checking invariants such as method postconditions. We will investigate their use in this section. 1. Consider the addDetails method. At the end, the keys (both name and phone number) should be in use. Add a suitable assertion statement to check this. Copyright (c) Aston University 2005–7 CS1410 JPD: Lab 7 5 (a) (b) Figure 1: Dialog boxes for exception handling. 2. Now let us run the program with assertions switched on. This is a run-time flag to the Java Virtual Machine. To switch it on, select the Run menu, then the Arguments tab and put -ea as an argument to the virtual machine (not to the program). When you run the program everything should work as normal (assuming the assertion is correctly written). Now we will change the program so that it no longer works correctly (in order to check that the assertion is triggered). Modify addDetails so that it adds an entry for just one key rather than two (by commenting out an appropriate line). Run the program again and add a new contact. The program should terminate with red text in the Console window describing an “Exception”, printing the message from the assert statement, and giving a trace of the method calls with links to their place in the files. 3. (Optional) Write a helper method consistentSize that checks whether the number of entries in the book (arranged uniquely by key) matches the numberOfEntries variable. Add an assertion to test this in addDetails. Copyright (c) Aston University 2005–7