480 likes | 635 Views
CE203 - Application Programming. Part 2. Exceptions 1. Exceptions are used for error handling and allow the handling of an error to be separated from its detection. The use of exceptions makes it easy to enforce uniform handling of errors in large programs.
E N D
CE203 - Application Programming Part 2 CE203 Part 2
Exceptions 1 Exceptions are used for error handling and allow the handling of an error to be separated from its detection. The use of exceptions makes it easy to enforce uniform handling of errors in large programs. Exceptions are intended for use in exceptional circumstances that prevent the normal execution of the program. If a user is asked to supply a number between 1 and 10 and types 11 he or she should be asked to try again, and it is not appropriate to use an exception. On the other hand, if a program cannot open a data file it is not possible to proceed further, so it would be appropriate to use an exception. CE203 Part 2
Exceptions 2 A method that detects an error may throw an exception, which may then be caught by the method that called it or by some higher level call; if the exception is not caught execution will be terminated with an error message (unless the exception occurs when an event-handler is being used in an applet, in which case the handling of that event will be aborted). In Java all exceptions are class objects and must be a member of the class Exception, or of some subclass of this class; a number of subclasses are provided in the standard library, for example NullPointerException, ArithmeticException and ArrayIndexOutOfBoundsException. CE203 Part 2
Exceptions 3 Here is a simple method which throws an exception if it cannot proceed normally: public static int quotient(int num, int den){ if (den==0) throw new DivideByZeroException(); return(num/den);} This method throws a new object of type DivideByZeroException if an argument is supplied that would result in a division by zero. CE203 Part 2
Exceptions 4 A section of code which calls a method that may throw an exception may be placed in a try block: try{ int c = quotient(a, b); System.out.println("The answer is " + c);} Such a block is normally followed by one or morecatch blocks: catch (DivideByZeroException d){ System.out.println(d.toString());} CE203 Part 2
Exceptions 5 If an exception is thrown between entry to and exit from a try block the execution of the block terminates; if there is a catch block whose argument type matches the type of the exception that block is executed. After termination of the catch block control resumes after the end of the last catch block. If there is no catch block with appropriate argument type the exception is propagated to the enclosing try block, if there is one; if an exception is not caught the program will terminate. CE203 Part 2
Exceptions 6 We now wish to define the DivideByZeroException class used in our example. This must be a subclass of Exception or of some other appropriate exception class from the library. It is sensible to use the ArithmeticException class as the superclass so that divide by zero exceptions may be caught by any catch blocks with argument type ArithmeticException as well as by catch blocks with argument type DivideByZeroException. CE203 Part 2
Exceptions 7 Since the DivideByZeroException class may be reused it should be written as a public class in a file of its own. It should normally have a constructor. public class DivideByZeroException extends ArithemticException{ public DivideByZeroException() { // body needed }} CE203 Part 2
Exceptions 8 The Exception class contains a private description string that should be initialised by the constructor. The ArithmeticException class (like most others in the standard library) has a constructor which takes a string argument, so our constructor should invoke this to initialise the string with an appropriate message: public class DivideByZeroException extends ArithemticException{ public DivideByZeroException() { super("you tried to divide by 0"); }} CE203 Part 2
Exceptions 9 The toString method inherited from the Exception class will return a string comprising the class name and the description string; our catch block used this to output the string. It is of course possible to provide a toStringmethod to replace the inherited one if we wish to generate a different string (in this case the constructor would not be needed). // alternative versionpublic class DivideByZeroException extends ArithemticException{ public String toString() { return("EXCEPTION - you tried to " + "divide by zero"); }} CE203 Part 2
Exceptions 10 If we want our exception class to generate a string of the form you tried to divide 17 by 0 we will need a constructor with an int argument: public class DivideByZeroException extends ArithemticException{ public DivideByZeroException() { super("you tried to divide by 0"); } public DivideByZeroException(int n) { super("you tried to divide " + n + " by 0"); }} CE203 Part 2
Exceptions 11 The throw statement in the quotient method would have to be modified to make use of the new constructor: public static int quotient(int num, int den){ if (den==0) throw new DivideByZeroException(num); return(num/den);} CE203 Part 2
Exceptions 12 If in a try block we wished to respond to divide by zero exceptions in one way and all other arithmetic exceptions in a different way we could provide two catch blocks: try{ // some arithmetic} catch(DivideByZeroException d){ // deal with divide by zero exception} catch(ArithmeticException a){ // deal with other arithmetic exceptions} CE203 Part 2
Exceptions 13 If there is more than one catch block whose argument matches the type of the exception that has been thrown then the one that appears first will be executed. Since DivideByZeroException is a subclass of the ArithmeticException class any divide by zero exception will indeed match both argument types so it is important that the two blocks in the example on the previous slide are written in the order shown. CE203 Part 2
Exceptions 14 Java 7 introduced a shortcut for handling multiple exception types in a single catch clause: try{ // some arithmetic + file handling} catch(DivideByZeroException|IOExceptiona){ // deal with both types of exception} CE203 Part 2
Exceptions 15 Afinallyblock may follow try/catch blocks. This is guaranteed to be executed if any portion of a try block is executed and can be used to release resources, close files, reset network connections, tidy up etc.: try{ // …} catch(Exception d){ // more than one catch block possible} finally { // always executed(even without catch block)} CE203 Part 2
try with Resources try ( Socket sock = new Socket(“155.25.13.1”,80); FileWrite file = new FileWriter(“toast”); ){ // …} catch(IOException e){ // } ... once control leaves the try block the resources are automatically closed (using their close method) CE203 Part 2
Throws Clauses 1 The declaration of a method that may throw an exception can have a throws clause indicating that an exception might be thrown. We could add such a clause to the declaration of quotient: public static int quotient(int num, int den) throws DivideByZeroException{ if (den==0) throw new DivideByZeroException(num); return(num/den);} CE203 Part 2
Throws Clauses 2 If we had chosen to implement the DivideByZeroException class as a direct subclass of Exception instead of ArithmeticException such a clause would have been compulsory. If a method can throw more than one type of exception these should be separated by commas in a throws clause: public static intmymethod(……) throws DivideByZeroException,InvalidDateException,IOException{ ………………} CE203 Part 2
Throws Clauses 3 If the designers of the language had adopted a disciplined approach throws clauses would be necessary for all methods that can throw exceptions, but this is unreasonable since the majority of methods written in any Java program will contain statements that could potentially throw exceptions. For example, a line of code such as a[i] = m/n; (where a is of type int[] and the other variables are of type int) could give rise to a null pointer exception (if a is null), an array index exception (if i is negative or too large) or an arithmetic exception (if n is zero). CE203 Part 2
Throws Clauses 4 It would be unrealistic to insist that every method containing a statement like the one on the previous slide has to include all of the possible exceptions in a throws clause. Hence the exception classes mentioned, along with several others, have been grouped together as subclasses of a class called RuntimeException. Exceptions from this class do not have to be specified in throws clauses. The occurrence of a run-time exception will usually indicate a bug in the program, whereas other exceptions, such as FileNotFoundException, are more likely to occur as the result of an external problem or incorrect data being supplied by the user. CE203 Part 2
Exceptions: Performance • Guarding against exceptions is free in Java • Throwing an exception is not free • Throw exceptions only in “exceptional” circumstances • Do not use them for checking simple conditions • Abnormal situation versus routine/expected conditions CE203 Part 2
Exceptions Summary Java exceptions are either checked or unchecked. Checkedexceptions have to be handled by the programmer: • the programmer either has to catch them or declare them • if this is not done, the compilation will fail • all IOExceptions are checked exceptions Uncheckedexceptions are different: • the programmer can choose to catch them or declare them • if this is not done, the compilation will still succeed • NumberFormatException is an unchecked exception CE203 Part 2
Example: A Date Class 1 We now wish to consider the addition of exception handling to a class that stores a date. We first present a version without exception handling: public class Date{ private int d, m, y; private static int[] daysInMonths = { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; private static boolean leap(int yr) { return yr%4==0 && (yr%100!=0 || yr%400==0); } CE203 Part 2
Example: A Date Class 2 public Date() { d = 21; m = 10; y = 2013; } public Date(intdy, int mo, int yr) { if (mo<1 || mo>12 || dy<1 ||dy>daysInMonths[mo] || mo==2 && dy==29 && !leap(yr)) { d = 1; m = 1; y = 2000; } else { d = dy; m = mo; y = yr; } } CE203 Part 2
Example: A Date Class 3 public int year() { return y; } public int month() { return m; } public int day() { return d; } public String toString() { return d + "/" + m + "/" + y; } // need more methods, e.g. advance} CE203 Part 2
Example: A Date Class 4 We wish to modify the constructor so that it throws an exception if an attempt is made to construct an invalid date. We must first declare a suitable exception class. Since a user who writes a line such as Date xmasDay = new Date(25, 12, 2013); will not want to use a try block nor have to provide a throws clause, our exception class should inherit from RuntimeException. We will provide two constructors allowing a different message to be generated if the user tries to initialise a date to 29th February of a non-leap year. CE203 Part 2
Example: A Date Class 5 public class InvalidDateException extends RuntimeException{ public InvalidDateException() { super("invalid date"); } public InvalidDateException(int yr) { super(yr + " is not a leap year"); }} CE203 Part 2
Example: A Date Class 6 We now modify the three-argument constructor in the Date class so that it throws an exception if any of the arguments are invalid: public Date(int dy, int mo, int yr){ if (mo<1 || mo>12 || dy<1 || dy>daysInMonths[mo]) throw new InvalidDateException(); if (mo==2 && dy==29 && !leap(yr)) throw new InvalidDateException(yr); d = dy; m = mo; y = yr;} CE203 Part 2
Example: A Date Class 7 There is no longer any point in including code to set the date to a default value in the constructor. Although the new object will hold an invalid date it will not be accessible in the program so will not lead to further errors. To see why this is the case we need to be aware of the sequence of actions that take place when a statement such as d = new Date(x, y, z); is executed. Firstly a new object is created, then it is initialised using the constructor and, finally, d is made to refer to it. If the constructor throws an exception the execution of the statement will not be completed and d will not refer to the new date. CE203 Part 2
Example: A Date Class 8 If a user of the Date class believes that his program will never attempt to construct an invalid date he can ignore invalid date exceptions when writing the program. If an exception is thrown the program will be terminated and he must search for the bug that has caused it. If, however, a date to be stored in a Date object is being provided as input, the exception can be used to detect invalid input, avoiding the need for the program to perform its own validation in addition to that performed by the constructor. We could write a method to input a date from the keyboard, as seen on the following slides. (You can also use the Scanner class for keyboard input!) CE203 Part 2
Example: A Date Class 9 public static Date getDate(){ boolean gotOne = false; Date d = null; // prepare for keyboard input BufferedReader buff = new BufferedReader( new InputStreamReader(System.in)); System.out.println("Please enter a date"); // loop until a valid date has been // entered while (!gotOne) { // loop body on next slides CE203 Part 2
Example: A Date Class 10 try { System.out.print("Day: ");intdy = Integer.parseInt(buff.readLine().trim()); System.out.print("Month: ");int mo = Integer.parseInt(buff.readLine().trim()); System.out.print("Year: ");int yr = Integer.parseInt(buff.readLine().trim()); d = new Date(dy, mo, yr);gotOne = true; } CE203 Part 2
Example: A Date Class 11 catch(InvalidDateException e) { System.out.println("Invalid date" + "- try again");} // I/O exception catch(IOException e) { System.out.println("IOException");} // deal with non-numeric input // (exception thrown by parseInt) catch(NumberFormatException e) { System.out.println("Invalid input" + "- try again");} } // end of while loop return d;} CE203 Part 2
Example: A Date Class 12 The static method parseInt from the Integer class was used in our method to convert a string comprising digits into an integer – this method throws an exception of type NumberFormatExceptionif the string does not represent a valid integer (an unchecked exception!) All the input and output methods in the Reader and Writer classes can throw an IOException – this is a checked exception, so we have to deal with it. CE203 Part 2
Example: A Date Class 13 If an exception is thrown, either by parseInt or the Dateconstructor (or the Reader), the end of the try block will not be reached and gotOne will not be set to true, so, after the output of a message by one of the catch blocks, the loop body will be executed again and the user will be prompted for more input. CE203 Part 2
Using Text Fields 1 Text fields are components that can be used for the display or input of a single line of text on an applet or panel. The java class JTextField has several constructors, including one which takes an argument of type int, specifying the width of the field (i.e. number of characters) and initialises the field to be empty. We illustrate the use of text fields with an applet to calculate the square of a number entered by the user. Since we wish to use the FlowLayout manager rather than the default BorderLayoutwe need to select the layout manager by applying the setLayoutmethod. CE203 Part 2
Using Text Fields 2 import javax.swing.*;import java.awt.*; import java.awt.event.* public class Arith extends JApplet{ JTextField input, result; public void init() { JLabel prompt = new JLabel( "Type a number and press return"); input = new JTextField(5); result = new JTextField(25); // make result field non-editable // so user cannot type in it result.setEditable(false); CE203 Part 2
Using Text Fields 3 // Arith.java continued // init method continued input.addActionListener( new TextHandler(this));setLayout(new FlowLayout());add(prompt);add(input);add(result); }} CE203 Part 2
Using Text Fields 4 A text field event occurs when the user completes the entry of text by pressing the carriage return key. To retrieve the contents of the text field in the actionPerformed method we apply getActionCommand to the ActionEvent argument. The text in our input field must be converted to a number using parseInt before the arithmetic is then performed. The setText method of the JTextField class will be used to clear the input field and display the result (or an error message) in the output field. Note that when the contents of components change the display is updated immediately so no repainting is involved. CE203 Part 2
Using Text Fields 5 // Arith.java continued class TextHandler implements ActionListener{ private Arith theApplet; public TextHandler(Arith app) { theApplet = app; } public void actionPerformed(ActionEvent e) { String text = e.getActionCommand(); String answer = null; // clear input field theApplet.input.setText(""); CE203 Part 2
Using Text Fields 6 // Arith.javaTextHandler class continued try { int n =Integer.parseInt(text.trim()); answer = "The square is " + n*n; } catch(NumberFormatException ex) { answer = "Invalid input"; } // display the answertheApplet.result.setText(answer); } } CE203 Part 2
Using Text Fields 7 If we wished to write an applet where the user has to enter a number in a text field and then press a button to invoke the arithmetic we would not be able to retrieve the contents of the text field by using getActionCommand in the actionPerformed method of the button-handler class, as this method would just return the text on the button. Instead we could retrieve the text by applying getText to the JTextField object. An outline of a possible actionPerformed method is presented on the following slide. CE203 Part 2
Using Text Fields 8 public void actionPerformed(ActionEvent e){ String text = theApplet.input.getText(); String answer = null; theApplet.input.setText(""); if (text.length()==0) answer = "Please enter a number"; else // try and catch blocks as before theApplet.result.setText(answer); } CE203 Part 2
JApplet Methods 1 We have already seen the use of init and paint methods in applets. These are methods of the JApplet class that are called by the applet container running in the browser; in order to do anything useful the programmer must write versions of these methods to replace the inherited ones. The JApplet class actually has five methods that can be overridden by the user: init, start, paint, stop and destroy. As we have already seen paint has an argument of type Graphics; the others have no arguments. All are declared as public void. CE203 Part 2
JApplet Methods 2 When an applet is loaded the initmethod is called followed by start and then paint. The initmethod is only called once and should be used to perform initialisation of instance variables and the setting up of components and registration of events that are to be detected. The start and paint methods may be called again under certain circumstances; in order to decide what to place in each of these methods it is necessary to understand these circumstances. CE203 Part 2
JApplet Methods 3 When a browser moves to another HTML page the applet container does not stop running; however the applet’s stop method will be called. This might typically contain code to suspend animations or threads. The start method will be called if the browser returns to the page so the starting up of any activities that are stopped in the stop method should be performed here to ensure that they are restarted. CE203 Part 2
JApplet Methods 4 The paint method will be called whenever the display needs to be updated. This might happen if the window has been closed and reopened or covered by another window and then revealed. (The paintComponent method of any JPanel objects will also be called in such circumstances.) The paint method can also be invoked indirectly from an event-handler if the display needs to change as a result of the event. The destroy method is called when the applet is about to be removed from memory – this normally happens when the browser is exited. This method should be used to release any resources. CE203 Part 2