Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Exceptions An exception is the occurrence of a detectable, abnormal situation that may lead to a system failure. Example: The following program fragment handles a very simple exception (division by 0) by sending a message to standard output: double length, area; System.out.println("Enter Length"); length = MyInput.readDouble(); System.out.println("Enter the area"); area =MyInput.readDouble(); if (length ==0) System.out.println("Division by 0"); else System.out.println("Width is "+(area/length)); This code is a simple fix for a simple runtime error. However, runtime errors come in all shapes, sizes and flavors, ranging from “division by zero,” to “file not found,” to various I/O errors. To handle runtime errors uniformly and efficiently, Java provides the try-throw-catch construction: Example: double length, area; try { System.out.println("Enter Length"); length = MyInput.readDouble(); if (length == 0) { Exception e = new Exception("Division by zero"); throw e; } System.out.println("Enter the area"); area =MyInput.readDouble(); System.out.println("Width is "+(area/length)); } catch(Exception e) { System.out.println(e.getMessage()); } System.out.println("All Done"); So what does this mean? First of all, notice that most (not all) of the code is contained in two blocks: a try block and a catch block: Try block try { System.out.println("Enter Length"); length = MyInput.readDouble(); if (length == 0) { Exception e = new Exception("Division by zero"); throw e; } System.out.println("Enter the area"); area =MyInput.readDouble(); System.out.println("Width is "+(area/length)); } Catch block catch(Exception e) { System.out.println(e.getMessage()); } Here is how the code works: If length equals 0 then 1. An object of class Exception is created and initialized with String “Division by zero.” 2. The object e is thrown (as a parameter) to the catch block. 3. Program control passes to the catch block. The remainder of the code in the try block is skipped. 4. The program resumes with the code following the catch block. If length is not equal to 0: 1. No Exception object is created. 2. The code in the catch block is skipped. The idea is simple: if an exception occurs, an object encapsulating information about the exception is created and passed (thrown) to a block of code that will handle the exception. In the example, the information contained in the object is the string “Division by zero.” In general, the try-throw-catch construction contains the following structures: The try block: try { code throw statement code } The throw statement: A throw statement creates an object of the class Exception. This Exception object contains information about the exception that has occurred. When an Exception object is thrown, the program branches to a catch block. There may be more than one catch block. Every exception should be caught by some catch block. catch block: catch(Exception e) { code } e is called the catch-block-parameter. Notice that e is an object of class Exception. There are Exception subclasses e.g. IOException, FileNotFoundException. The Exception class is the root class of all other exception classes. After the code in the catch-block is executed the program continues with the code following the catch block. getMessage() Method: Every Exception object contains a String attribute and a constructor with a String parameter: new Exception(“Hi, I’m a string”); The method getMessage() returns that string stored in the exception object: e.getMessage() Important: Do not think that exception handling is just a fancy if-then-else statement. A try-block can send a message to the catch-block, but an if-clause cannot communicate with an else-clause. Java Exception Hierarchy Here is a partial view of the Exception class hierarchy. As you know, all classes extend Object. Under Object is the Throwable class. Both Exception and Error extend Throwable. The Error class represents internal system errors (rare) like Linkage errors. There is not much you can do about system errors. Object Throwable Exception ClassNotFound Exception IOException ArithmeticException RuntimeException NullPointerException Error AWTException IndexOutOfBounds Exception FileNotFound Exception System generated exceptions Every exception does not necessitate a throw statement. If a standard exception occurs (file not found, array out of bounds, IO exception, arithmetic exception, etc.) the system automatically throws the exception. Some system exceptions (e.g., RunTime Exceptions) do not require handling but, as you will shortly see, other system exceptions do. Example: int [] list = new int[5]; for (int i = 0;i < 5; i++) list[i] = i*i; for (int i = 0; i <= 5; i++) System.out.println(list[i]); You might have noticed that in the second for-loop the index of the array, list, will eventually go out of bounds. If this fragment were to run within a program, the Java Virtual Machine would automatically throw an IndexOutofBoundsException exception. Handling of this RuntimeException exception is not required. However, because there is no catch block in the program to handle the exception, the final result is a rather inelegant crash. 0 1 4 9 16 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException at ArrayNoCatch.main(ArrayNoCatch.java:11) Press any key to continue . . . A more graceful scenario would have the program catch and handle the exception: int [] list = new int[5]; try // notice a throw clause is not included { for (int i = 0;i < 5; i++) list[i] = i*i; for (int i = 0; i<= 5; i++) System.out.println(list[i]); } catch (IndexOutOfBoundsException e) { System.out.println(“Array index out of bounds”); System.out.println("Whoops"); } The IndexOutOfBounds error is now handled by the catch block. 0 1 4 9 16 Array index out of bounds Whoops Press any key to continue . . . The exception e in the catch block is of type IndexOutOfBoundsException, and because IndexOutOfBoundsException is-a Exception, the code catch (Exception e), can be used in place of catch (IndexOutOfBoundsException e). In other words, an IndexOutOfBoundsException object can be upcast to an Exception object. Also, the catch block need not use the getMessage() method. Any exception handling mechanism will do. Example: In the following segment, the system automatically throws a NullPointerException exception. The string returned by getMessage() is simply null. Square s = null; // Square is a valid class. try { System.out.println(s.area()); } catch(Exception e) // or catch (NullPointerException e) { System.out.println(e.getMessage()); } System.out.println("All Done"); Output: null All Done Since s is not instantiated, s is null. Thus s.area() causes a NullPointerException exception. The Java Machine throws this exception automatically. Example: You might expect that the Java Virtual Machine throws some kind of arithmetic or division-by-zero error if the variable length is set to 0.0 in the following fragment. However, that is not the case. double length, width, area; try { System.out.println("Enter Length"); length = MyInput.readDouble(); System.out.println("Enter the area"); area =MyInput.readDouble(); System.out.println("Width is "+(area/length)); //division by 0 ???? } catch(Exception e) { System.out.println(e.getMessage()); } System.out.println("All Done"); The program produces the following output: Enter Length 0.0 Enter the area 25.0 Width is Infinity All Done Recall that in Java, type double contains the value Infinity. However, type int does not contain the value Infinity. If the data type in the previous example is changed to int, the system will automatically throw an ArithmeticException exception. The exception should be caught. int length, width, area; try { System.out.println("Enter Length"); length = MyInput.readInt(); System.out.println("Enter the area"); area =MyInput.readInt(); System.out.println("Width is "+(area/length)); } catch(ArithmeticException e) { System.out.println("Error: "+ e.getMessage()); } System.out.println("All Done"); Example: When accepting user input, a robust program should always check the validity of the input. If a user is prompted for an integer, there is no guarantee that he/she will not accidentally type a character. If a user enters invalid data, a program should handle the error and not crash. The following code uses exception handling to check interactive input. Notice the use of the wrapper class Integer. Input from the user arrives in the form of a String x. Then, x is passed to the parseInt() method. If x is numeric, an integer value is returned; if not, the system throws a NumberFormatException exception. boolean done= false; while (!done) { try { System.out.print("Enter an integer: "); x = MyInput.readString(); y = Integer.parseInt(x); if (y==0) done = true; else System.out.println("Square: " + (y*y)); } catch (NumberFormatException e) { System.out.println("Illegal number: "+e.getMessage()+". Re-enter" ); } } Here is some sample output: Enter an integer: 23 Square: 529 Enter an integer: aaa Illegal number: aaa. Re-enter Enter an integer: 18 Square: 324 Enter an integer: 23e Illegal number: 23e. Re-enter Enter an integer: 0 Multiple Catch Blocks Several catch blocks can be associated with a single try block: try { statements } catch ( ArithmeticException e) { statements } catch ( NullPointerException e) { statements } catch ( Exception e) { statements } In this case, the first catch block with parameter matching the type of thrown exception catches the exception. Example: The following fragment will print the square root of (non-negative) numbers. Exceptions occur when the user enters a negative number or, possibly, a nonnumeric string. String x = new String(); int y; boolean done= false; while (!done) { try { System.out.print("Enter an integer: "); x = MyInput.readString(); y = Integer.parseInt(x); if (y==0) done = true; else if (y < 0) throw new Exception("Negative Number. Re-enter"); else System.out.println("Square root: " + (Math.sqrt(y))); } catch (NumberFormatException e) { System.out.println("Illegal number: "+ e.getMessage() +". Re-enter" ); } catch (Exception e) { System.out.println( e.getMessage()); } } If a user enters abcd as input, the Java Machine will throw a NumberFormatException exception when the parseInteger method is called. The first catch block will catch the exception. On the other hand, if the user input is –54, the statement if (y < 0) throw new Exception("Negative Number. Re-enter"); will cause an exception (type Exception) to be thrown. The first catch block will not catch this exception since the parameter is of type NumberFormatException. However, the second catch block with parameter type Exception will catch the exception. (Note that the Math.sqrt(double x) method will not throw an exception if x is negative. Instead, the function returns the value NaN (Not a Number). Sample output: Enter an integer: 4 Square root: 2.0 Enter an integer: -4 Negative Number. Re-enter Enter an integer: ee Illegal number: ee. Re-enter Enter an integer: 0 Example The following fragment (which does nothing!) has several catch blocks corresponding to various types of exceptions including a contrived exception which occurs if user input is greater than ten. No throw statement is necessary for an ArithmeticException or an IndexOutOfBound exception. The system automatically throws those exceptions if any occur. try { int a, b, c; int [] s = new int[3]; System.out.println("Enter two numbers a, b"); a= MyInput.readInt(); b= MyInput.readInt(); if (a>10 || b > 10 ) throw new Exception("number is greater than 10"); c = a/b; //possible division by 0 s[c] = a; // possible index out of bounds System.out.println(a+ " " +b+ " " +c+ " " +s[c]); } catch ( ArithmeticException e) { System.out.print (e.getMessage()); System.out.println(" Arithmetic exception"); } catch ( IndexOutOfBoundsException e) { System.out.print (e.getMessage()); System.out.println(" Array exception"); } catch ( Exception e) { System.out.println(e.getMessage()); } Unchecked Exceptions Runtime exceptions and Error exceptions (see the hierarchy above) fall into the category of unchecked exceptions. Unchecked exceptions, like division by zero or an array index out of bounds, can occur anywhere in any method. An unchecked exception is the most common type of exception. The table below enumerates some of the more common unchecked exceptions. There are many more. Some Common Unchecked Runtime Exceptions ArithmeticException ArrayIndexOutOfBoundsException ArrayStoreException ClassCastException IllegalArgumentException NullPointerException NumberFormatException StringIndexOutOfBounds Some arithmetic error e.g. division by zero. Invalid index value for an array. Invalid type for an array element. Invalid cast. Invalid argument when calling a method. Attempt to dereference a null pointer. Invalid string in a conversion to a number. Invalid index value for a String. As previously mentioned, you can either ignore unchecked exceptions or handle them. The following code segment causes the system to throw an IndexOutOfBoundsException exception. The code completely ignores the possibility of an exception. int [] list = new int[5]; for (int i = 0;i < 5; i++) list[i] = i * i; for (int i = 0; i<= 50; i++) System.out.println(list[i]); When embedded in a program, the rather inelegant output is: 0 1 4 9 16 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException at ArrayCatch.main(ArrayCatch.java:17) Moreover, if a method explicitly throws an unchecked exception, it is not necessary to handle the exception. An explicit throw statement appears in the code below but no handling mechanism is present. int [] list = new int[5]; for (int i = 0;i < 5; i++) list[i] = i*i; for (int i = 0; i<= 50; i++) if (i >= 5) throw new IndexOutOfBoundsException("Oops! Out of Bounds"); else System.out.println(list[i]); Notice the "Oops! Out of Bounds" message appears in the program output, that is when the program crashes: 0 1 4 9 16 Exception in thread "main" java.lang.IndexOutOfBoundsException: Oops! Out of Bounds at ArrayCatch.main(ArrayCatch.java:15) The Throws Clause An exception that is not unchecked is called a checked exception. If a checked exception is thrown in a method, the method must either: catch (try-catch construction) the exception or list the exception in a throws clause appended to the method signature. A throws clause enumerates the type of exceptions a method may throw. If a method does not catch a checked exception, the exception object is passed to the caller. The caller must either handle the exception or list the exception in a throws clause. Checked exceptions can be passed along the chain of method calls right up to the main method and finally to the system. Example: The class Square below has no exception handling mechanism. Any value, positive, zero, or negative, is an acceptable value for the variable side. public class Square { int side; public Square() { side = 1; } public void setSide(int x) { side = x; } public int area() { return side * side; } } public class TestSquare { public static void main(String[] args) { int side; Square s = new Square(); System.out.println("Enter side"); side = MyInput.readInt(); s.setSide(side); System.out.println("Area:"+ s.area()); } } The next implementation of Square throws and catches an exception just in case side is not positive. Everything is handled in setSide(). public class Square { int side; public Square() { side = 1; } public void setSide(int x) { try { if (x <= 0) throw new Exception("Side must be positive"); else side = x; } catch (Exception e) { System.out.println(e.getMessage()); System.exit(0); } } public int area() { return side*side; } } Sample Run: Enter side -8 Side must be positive Press any key to continue . . In this next implementation of Square, method setSide throws an exception if side is not positive. However, the exception is not handled with a try-catch structure. Instead, a throws clause is added to the method signature. If an exception occurs, the exception is passed to the caller. Look closely at the code. It does not compile. public class Square { int side; public Square() { side = 1; } public void setSide(int x) throws Exception { if (x <= 0) throw new Exception("Side must be positive"); else side = x; } public int area() { return side*side; } } public class Tester { public static void main(String[] args) { int side; Square s = new Square(); System.out.println("Enter side"); side = MyInput.readInt(); s.setSide(side); System.out.println("Area:"+ s.area()); } } Compilation of the Square class causes no problem. The method setSide throws an exception and contains a throws clause. Square has fulfilled its contract. However, an attempt to compile Tester.java results in the following error message: C:\Java Applications\Tester.java:11: unreported exception java.lang.Exception; must be caught or declared to be thrown s.setSide(side); ^ 1 error When an exception is thrown in setSide(), the exception is passed to the caller main(). The compilation error occurred because method main() neither handled the exception nor included a throws clause for the exception, even though main() was responsible for the exception. Two remedies are detailed below. main() handles the exception public class Tester { public static void main(String[] args) { int side; Square s = new Square(); System.out.println("Enter side"); side = MyInput.readInt(); try { s.setSide(side); System.out.println("Area:"+ s.area()); } catch (Exception e) { System.out.println(e.getMessage()); } } } main() includes a throw clause public class Tester { public static void main(String[] args) throws Exception { int side; Square s = new Square(); System.out.println("Enter side"); side = MyInput.readInt(); s.setSide(side); System.out.println("Area:"+ s.area()); } } //The exception handled by the program: //The exception passed to the Java Virtual Machine: Output: Output: Enter side -4 Exception in thread "main" java.lang.Exception: Side must be positive at Square.setSide(Square.java:13) at Tester.main(Ex2.java:12) Enter side -4 Side must be positive Creating an Exception class: You can create your own exception class by extending Exception. The following example creates a class DivisionByZero. Notice the calls to the super class (Exception) in the two constructors. Example public class DivisionByZero extends Exception { //constructors public DivisionByZero() { super("You have attempted a division by zero"); } public DivisionByZero(String s) { super(s); } } public class DivisionByZeroTest { public static void main(String args[]) { double length, area; try { System.out.println("Enter Length"); length = MyInput.readDouble(); if (length == 0) throw new DivisionByZero("Division by zero exception"); System.out.println("Enter the area"); area =MyInput.readDouble(); System.out.println("Width is "+(area/length)); } catch(DivisionByZero e) { System.out.println(e.getMessage()); } System.out.println("All Done"); } }