MT311 Java Application Development and Programming Languages Li Tak Sing(李德成) Exception Handling Exception is a runtime error. When a run time error appears, an exception is thrown. For example, when you run the following code: Integer i=null; i.toString(); an exception would be thrown because you are trying to invoke a method of a null object. Exception Handling In fact the following message would be displayed: Exception in thread "main" java.lang.NullPointerException at lecture15_11_2005.Main.main(Main.java:29) This is the default exception handling, i.e., to print out a message showing where the exception is thrown and what type of exception is thrown. Exception Handling If you want to handle an exception differently, then you can use the try-catch block. Consider the following code: try { Integer i=null; System.out.println(i.toString()); } catch (Exception e) { System.out.println("an error occurs"); } try ... catch The above statements state that try the statements in the try block. Then if an exception is thrown and it is of type Exception, then, run the statements in the catch block. Checked and unchecked exception There are two kinds of exceptions, namely checked and unchecked. Checked exceptions are all subclass of Exception. Unchecked exceptions are subclass of either Error or RuntimeException. Error refers to errors of the Java system itself and therefore we cannot handle it. RuntimeException are those that errors that can happen anywhere in a program when a program is executed. Unchecked Exception For example, NullPointerException can happen anywhere in the program when you are using an object variable. For this kind of errors, Java does not require you to handle it. Of course, you may still choose to handle it. If you do not handle an unchecked error and that error occurs, the default handler will be used which is to stop the program and display a message about this error. Unchecked Exception So both the following codes are correct: public void method() { public void method() { try { Integer i=null; Integer i=null; System.out.println(i.toString()); System.out.println(i.toString()); } System.out.println("error2"); catch () { } System.out.println("error"); } System.out.println("error2"); } the 'throw' keyword In the last exception, the NullPointerException was generated when the Java runtime system discovered an error. In fact, we can create any exception anywhere we want by using the 'throw' key word. the 'throw' keyword Consider the following program: ..... if (....) { throw new NullPointerException(); } ... This statement will throw the NullPointerException when the condition is satisfied. Checked exceptions All subclasses of Exception other than those of RuntimeError's are checked Exception. Unlike unchecked errors which can occur nearly everywhere in a program, checked errors usually occur at only a few points in a program. Checked Exceptions Unlike unchecked exceptions, you must handle all checked exceptions. There are two ways to handle a checked exception in a method, either you handle it locally or you have the exception handled by the caller of the method. Checked Exceptions For example, an IOException refers to an exception that occurs during an IOException which is a checked exception. So if you have code like this: public void method() { if (...) throw new IOException(); } the compiler would report an error saying that you did not handle the IOException. Handling a checked exception locally To handle a checked exception locally, you must include the statements that would generate that exception inside a try-catch block: public void method() { try { if (...) throw new IOException(); } catch (IOException e) { ........ } } Letting the caller to handle the exception Another way to handle an exception is to let the caller to handle it. In this case, you must declare the method would throw such exception using the 'throws' keyword: Letting the caller to handle the exception public void method() throws IOException { if (...) throw new IOException(); } Now, there is no need to include a try-catch block here because the exception should now be handled by whatever method that called this one Letting the caller to handle an exception So the caller of the above method now itself has two choices, either to handle it locally or to have it handled by its own caller by using the 'throws' keyword. public class ABC { public void method1() throws IOException { ..... throw new IOException(); } public void method2() throws IOException { ..... method1(); } public void method3() throws IOException { ..... method2(); } public void method4() { ..... try { method3(); } catch (IOException e) { .....} } } Checked Exception If you study the documents for methods that would handle IO, security, etc, then you will see that most of these methods use the 'throws' keyword to tell you that they may throw certain exceptions when problems occur. So if you want to use these methods, you must either handle these exception locally using the try-catch block or you use the 'throws' keyword yourself to let the caller of the method you just wrote to handle it. Checked Exception Assume that you want to open a file to read the content, then you can write: public void String readFile(String filename) { try { FileReader reader=new FileReader(....); ..... return result; } catch (IOException e) { return null; //an error occurs and therefore a null is returned } } Checked Exception Or you can write the method like this: public void String readFile(String filename) throws IOException { FileReader reader=new FileReader(....); ..... return result; } Checked Exception In the former case, the user of the method do not have to handle any exception. Actually, the user of the method would not know that there might or might not have errors. In the latter case, the user has to handle any possible error generated in the method or it itself has to use the 'throws' keyword to let the caller to handle it. So be careful about the difference of 'throw' and 'throws' 'throw' is an action. This is to actually throw an exception: throw new IOException(); //an IOException is thrown 'throws' is a declaration. This is to declare that a method may throw such exception: public void method() throws IOException() // this method may // throw IOException, so the caller of this method must handle it 'throw' Therefore, you can create your own exception and then throw it wherever you want. Creating your own exceptions Now, assume that you are writing a method to calculate the amount of interest you are going to pay for a given amount of principal, interest rate and the year of loan. So the method look like this: static public double interest(double principal, double rate, double length) {...} Creating your own exception Obviously, the result of the method would be meaningless if either the principal, the interest rate or the length of loan is negative. Therefore we create three exceptions, known as NegativePrincipal, NegativeRate, NegativeLength. Creating your own exceptions public class NegativePrincipal extends Exception { ..... } public class NegativeRate extends Exception { .... } public class NegativeLength extends Exception { ... } Creating your own exception static public double interest(double principal, double rate, double length) throws NegativePrincipal, NegativeRate, NegativeLength { if (principal<0) throw new NegativePrincipal(); ....... } So the user the method may look like this: try { double interest=interest(1,-2,3); System.out.println("the interest is "+interest); } catch (NegativePrincipal e) { System.out.println("the principal is negative"); } catch (NegativeRate e) { System.out.println("the rate is negative"); } catch (NegativeLength e) { System.out.println("the length is negative"); } Calling the method Many catch blocks If a try block is ended with more than one catch block, then each of the catch block will be tried until there is a match. try { double interest=interest(1,-2,3); System.out.println("the interest is "+interest); } catch (Exception e) { System.out.println("an exception has been thrown"); } catch (NegativePrincipal e) { System.out.println("the principal is negative"); } catch (NegativeRate e) { System.out.println("the rate is negative"); } catch (NegativeLength e) { System.out.println("the length is negative"); } the finally block A try block can also be ended with a finally block. If a try block has a finally block, then the code will be executed after the code in the try block has been executed or after the code in a catch block is executed if an exception has been thrown. finally This means that the code in the finally block will always be executed even if the following things happen: – – the return statement is executed inside the try block or a catch block an exception is thrown inside the try block public static void method(int i) { try { System.out.println("position 1"); if (i==1) { throw new IOException(); } System.out.println("position 2"); } catch (IOException e) { System.out.println("position 3"); } finally { System.out.println("position 4"); } } finally finally The output of the calling of the method: method(1): position 1 position 3 position 4 finally The output of the calling of the method: method(2): position 1 position 2 position 4 public static int method(int i) { try { System.out.println("position 1"); if (i==1) { throw new IOException(); } else if (i==2) { return 2; } System.out.println("position 2"); return 3; } catch (IOException e) { System.out.println("position 3"); return 4; } finally { System.out.println("position 4"); } } Finally the output of the following calls: System.out.println(method(1)); System.out.println(method(2)); System.out.println(method(3)); Finally position 1 position 3 position 4 4 position 1 position 4 2 position 1 position 2 position 4 3