Chapter 9 Error handling with exceptions Syntax errors

  • Slides: 28
Download presentation
Chapter 9: Error handling with exceptions ● ● ● Syntax errors can be detected

Chapter 9: Error handling with exceptions ● ● ● Syntax errors can be detected at compile time by compiler But there are other run-time errors that is not possible to be detected at compile time There is not a well-defined error handling in languages like C: – – You set a flag in a method where some run-time errors happened and the recipient is responsible to interpret and make action on it Those error checks makes a program hard to read and maintain

Better way ● ● ● ● Separate normal behavior from exceptional cases Enforce exceptional

Better way ● ● ● ● Separate normal behavior from exceptional cases Enforce exceptional handling in the languageses Ada introduced Exception handling in the language C++ bases on Ada And Java is based on C++ Exceptions in Java are objects that like other objects are created by new Exceptions are thrown and are processed by Exception halders

Example Void do. Something(T t) throws Null. Pointer. Exception{ if(t == null) throw new

Example Void do. Something(T t) throws Null. Pointer. Exception{ if(t == null) throw new Null. Pointer. Exception(); . . throw new Null. Pointer. Exception("t = null"); } When t is null (i. e. not initialized), an exception is thrown (Null. Pointer. Exception) ● Execution of do. Something is stopped and controls returns to the client code of do. Something. ● Client code may have defined an exception handler. In this case that handler is activated. ● If client code does not defined an exception handler, its client is checked. This chain continues until an exception handler is found or if there is not any, java default handler is execuited. ●

Try-Catch blocks try { // Code that might generate exceptions } catch(Type 1 id

Try-Catch blocks try { // Code that might generate exceptions } catch(Type 1 id 1) { // Handle exceptions of Type 1 } catch(Type 2 id 2) { // Handle exceptions of Type 2 } catch(Type 3 id 3) { // Handle exceptions of Type 3 } // etc. . . When an exception occured, control goes to a catch block with the exception type matching with the generated exception ● Control never goes back to the point where exception occurred (termination philosophy) ●

Defining exceptions import com. bruceeckel. simpletest. *; class Simple. Exception extends Exception {} public

Defining exceptions import com. bruceeckel. simpletest. *; class Simple. Exception extends Exception {} public class Simple. Exception. Demo { private static Test monitor = new Test(); public void f() throws Simple. Exception { System. out. println("Throw Simple. Exception from f()"); throw new Simple. Exception(); } public static void main(String[] args) { Simple. Exception. Demo sed = new Simple. Exception. Demo(); try { sed. f(); System. out. println(“no exception”); } catch(Simple. Exception e) { System. err. println("Caught it!"); } monitor. expect(new String[] { "Throw Simple. Exception from f()", "Caught it!" }); } } ///: ~

Defining exceptions with constructors class My. Exception extends Exception { public My. Exception() {}

Defining exceptions with constructors class My. Exception extends Exception { public My. Exception() {} public My. Exception(String msg) { super(msg); } } public class Full. Constructors { private static Test monitor = new Test(); public static void f() throws My. Exception { System. out. println("Throwing My. Exception from f()"); throw new My. Exception(); } public static void g() throws My. Exception { System. out. println("Throwing My. Exception from g()"); throw new My. Exception("Originated in g()"); } public static void main(String[] args) { try { f(); } catch(My. Exception e) { e. print. Stack. Trace(); } try { g(); } catch(My. Exception e) { e. print. Stack. Trace(); } monitor. expect(new String[] { "Throwing My. Exception from f()", "My. Exception", "%% tat Full. Constructors. f\(. *\)", "%% tat Full. Constructors. main\(. *\) "Throwing My. Exception from g()", "My. Exception: Originated in g()", "%% tat Full. Constructors. g\(. *\)", "%% tat Full. Constructors. main\(. *\) }); } } ///: ~

Defining exceptions with more features class My. Exception 2 extends Exception { private int

Defining exceptions with more features class My. Exception 2 extends Exception { private int x; public My. Exception 2() {} public My. Exception 2(String msg) { super(msg); } public My. Exception 2(String msg, int x) { super(msg); this. x = x; } public int val() { return x; } public String get. Message() { return "Detail Message: "+ x + " "+ super. get. Message(); } } public class Extra. Features { private static Test monitor = new Test(); public static void f() throws My. Exception 2 { System. out. println("Throwing My. Exception 2 from f()"); throw new My. Exception 2(); } public static void g() throws My. Exception 2 { System. out. println("Throwing My. Exception 2 from g()"); throw new My. Exception 2("Originated in g()"); } public static void h() throws My. Exception 2 { System. out. println("Throwing My. Exception 2 from h()"); throw new My. Exception 2("Originated in h()", 47); } public static void main(String[] args) { try { f(); } catch(My. Exception 2 e) { e. print. Stack. Trace(); } try { g(); } catch(My. Exception 2 e) { e. print. Stack. Trace(); } try { h(); } catch(My. Exception 2 e) { e. print. Stack. Trace(); System. err. println("e. val() = " + e. val()); } monitor. expect(new String[] { "Throwing My. Exception 2 from f()", "My. Exception 2: Detail Message: 0 null", "%% tat Extra. Features. f\(. *\)", "%% tat Extra. Features. main\(. *\)", "Throwing My. Exception 2 from g()", "My. Exception 2: Detail Message: 0 Originated in g()", "%% tat Extra. Features. g\(. *\)", "%% tat Extra. Features. main\(. *\)", "Throwing My. Exception 2 from h()", "My. Exception 2: Detail Message: 47 Originated in h()" "%% tat Extra. Features. h\(. *\)", "%% tat Extra. Features. main\(. *\)",

Exception specification We should specify the type of exceptions that a method throws. ●

Exception specification We should specify the type of exceptions that a method throws. ● This information is used by client programmer to create catch blocks ● void f() throws Too. Big, Too. Small, Div. Zero { //. . . If a method causes an (checked) exception, and it does not handle it, compiler forces to put it in the throws part ● Also compiler forces client code to have a catch block, or throw the exception ●

Exception class interface public class Exception. Methods { private static Test monitor = new

Exception class interface public class Exception. Methods { private static Test monitor = new Test(); public static void main(String[] args) { try { throw new Exception("My Exception"); } catch(Exception e) { System. err. println("Caught Exception"); System. err. println("get. Message(): " + e. get. Message()); System. err. println("get. Localized. Message(): " + e. get. Localized. Message()); System. err. println("to. String(): " + e); System. err. println("print. Stack. Trace(): "); e. print. Stack. Trace(); } monitor. expect(new String[] { "Caught Exception", "get. Message(): My Exception", "get. Localized. Message(): My Exception", "to. String(): java. lang. Exception: My Exception", "print. Stack. Trace(): ", "java. lang. Exception: My Exception", "%% tat Exception. Methods. main\(. *\)" }); } } ///: ~

Rethrowing an exception public class Rethrowing { private static Test monitor = new Test();

Rethrowing an exception public class Rethrowing { private static Test monitor = new Test(); public static void f() throws Exception { System. out. println("originating the exception in f()"); throw new Exception("thrown from f()"); } public static void g() throws Throwable { try { f(); } catch(Exception e) { System. err. println("Inside g(), e. print. Stack. Trace()"); e. print. Stack. Trace(); throw e; // 17 // throw e. fill. In. Stack. Trace(); // 18 } } public static void main(String[] args) throws Throwable { try { g(); } catch(Exception e) { System. err. println( "Caught in main, e. print. Stack. Trace()"); e. print. Stack. Trace(); } monitor. expect(new String[] { "originating the exception in f()", "Inside g(), e. print. Stack. Trace()", "java. lang. Exception: thrown from f()", "%% tat Rethrowing. f(. *? )", "%% tat Rethrowing. g(. *? )", "%% tat Rethrowing. main(. *? )", "Caught in main, e. print. Stack. Trace()", "java. lang. Exception: thrown from f()", "%% tat Rethrowing. f(. *? )", "%% tat Rethrowing. g(. *? )", "%% tat Rethrowing. main(. *? )" }); } } ///: ~

Rethrowing an exception (cont. ) ● When line 17 is commented and line 18

Rethrowing an exception (cont. ) ● When line 17 is commented and line 18 in un-commented: originating the exception in f() Inside g(), e. print. Stack. Trace() java. lang. Exception: thrown from f() at Rethrowing. f(Rethrowing. java: 9) at Rethrowing. g(Rethrowing. java: 12) at Rethrowing. main(Rethrowing. java: 23) Caught in main, e. print. Stack. Trace() java. lang. Exception: thrown from f() at Rethrowing. g(Rethrowing. java: 18) at Rethrowing. main(Rethrowing. java: 23)

Rethrowing a different exception public static void main(String[] args) throws Two. Exception { try

Rethrowing a different exception public static void main(String[] args) throws Two. Exception { try { f(); } catch(One. Exception e) { class Two. Exception extends Exception { System. err. println( public Two. Exception(String s) { super(s); } "Caught in main, e. print. Stack. Trace()"); } e. print. Stack. Trace(); throw new Two. Exception("from main()"); public class Rethrow. New { } private static Test monitor = new Test(); monitor. expect(new String[] { public static void f() throws One. Exception { "originating the exception in f()", System. out. println("originating the exception in f()"); "Caught in main, e. print. Stack. Trace()", throw new One. Exception("thrown from f()"); "One. Exception: thrown from f()", } "tat Rethrow. New. f(Rethrow. New. java: 18)", "tat Rethrow. New. main(Rethrow. New. java: 22)", "Exception in thread "main" " + "Two. Exception: from main()", "tat Rethrow. New. main(Rethrow. New. java: 28)" }); } } class One. Exception extends Exception { public One. Exception(String s) { super(s); } }

Exception chaining class Dynamic. Fields. Exception extends Exception {} public class Dynamic. Fields {

Exception chaining class Dynamic. Fields. Exception extends Exception {} public class Dynamic. Fields { private static Test monitor = new Test(); private Object[][] fields; public Dynamic. Fields(int initial. Size) { fields = new Object[initial. Size][2]; for(int i = 0; i < initial. Size; i++) fields[i] = new Object[] { null, null }; } public String to. String() { String. Buffer result = new String. Buffer(); for(int i = 0; i < fields. length; i++) { result. append(fields[i][0]); result. append(": "); result. append(fields[i][1]); result. append("n"); } return result. to. String(); } private int has. Field(String id) { for(int i = 0; i < fields. length; i++) if(id. equals(fields[i][0])) return i; return -1; } private int get. Field. Number(String id) throws No. Such. Field. Exception { int field. Num = has. Field(id); if(field. Num == -1) throw new No. Such. Field. Exception(); return field. Num; } private int make. Field(String id) { for(int i = 0; i < fields. length; i++) if(fields[i][0] == null) { fields[i][0] = id; return i; } // No empty fields. Add one: Object[][]tmp = new Object[fields. length + 1][2]; for(int i = 0; i < fields. length; i++) tmp[i] = fields[i]; for(int i = fields. length; i < tmp. length; i++) tmp[i] = new Object[] { null, null }; fields = tmp; // Reursive call with expanded fields: return make. Field(id); }

Exception chaining (cont. ) public Object get. Field(String id) throws No. Such. Field. Exception

Exception chaining (cont. ) public Object get. Field(String id) throws No. Such. Field. Exception { return fields[get. Field. Number(id)][1]; } public Object set. Field(String id, Object value) throws Dynamic. Fields. Exception { if(value == null) { // Most exceptions don't have a "cause" constructor. // In these cases you must use init. Cause(), // available in all Throwable subclasses. Dynamic. Fields. Exception dfe = new Dynamic. Fields. Exception(); dfe. init. Cause(new Null. Pointer. Exception()); throw dfe; } int field. Number = has. Field(id); if(field. Number == -1) field. Number = make. Field(id); Object result = null; try { result = get. Field(id); // Get old value } catch(No. Such. Field. Exception e) { // Use constructor that takes "cause": throw new Runtime. Exception(e); } fields[field. Number][1] = value; return result; }

Exception chaining (cont. ) monitor. expect(new String[] { "null: null", "d: A value for

Exception chaining (cont. ) monitor. expect(new String[] { "null: null", "d: A value for d", "number: 47", "number 2: 48", "d: A new value for d", "number: 47", "number 2: 48", "number 3: 11", "A value for d", "Exception in thread "main" " + "java. lang. Runtime. Exception: " + "java. lang. No. Such. Field. Exception", "tat Dynamic. Fields. main(Dynamic. Fields. java: 98)" "Caused by: java. lang. No. Such. Field. Exception", "tat Dynamic. Fields. get. Field. Number(" + "Dynamic. Fields. java: 37)", "tat Dynamic. Fields. get. Field(Dynamic. Fields. java: 5 "tat Dynamic. Fields. main(Dynamic. Fields. java: 96)" }); public static void main(String[] args) { Dynamic. Fields df = new Dynamic. Fields(3); System. out. println(df); try { df. set. Field("d", "A value for d"); df. set. Field("number", new Integer(47)); df. set. Field("number 2", new Integer(48)); System. out. println(df); df. set. Field("d", "A new value for d"); df. set. Field("number 3", new Integer(11)); System. out. println(df. get. Field("d")); Object field = df. get. Field("a 3"); // Exception } catch(No. Such. Field. Exception e) { throw new Runtime. Exception(e); } catch(Dynamic. Fields. Exception e) { throw new Runtime. Exception(e); } }

Standard java exceptions

Standard java exceptions

Runtime Exceptions (un-catched exceptions) public class Never. Caught { private static Test monitor =

Runtime Exceptions (un-catched exceptions) public class Never. Caught { private static Test monitor = new Test(); static void f() { throw new Runtime. Exception("From f()"); } static void g() { f(); } public static void main(String[] args) { g(); No need to have monitor. expect(new String[] { "Exception in thread "main" " + "java. lang. Runtime. Exception: From f()", " at Never. Caught. f(Never. Caught. java: 7)", " at Never. Caught. g(Never. Caught. java: 10)", " at Never. Caught. main(Never. Caught. java: 13)" }); } } ///: ~ a try-catch block here

Runtime Exceptions (cont. ) Runtime exceptions and its subclasses can be ignored ● This

Runtime Exceptions (cont. ) Runtime exceptions and its subclasses can be ignored ● This is because runtime exceptions represents a programming error ●An error you can't control (nullpointer exception) ●An error in programming that should be checked by programmer but it is forgotten (Array. Index. Out. Bounds. Exception) ●

Performing cleanup with finally try { // The guarded region: Dangerous activities // that

Performing cleanup with finally try { // The guarded region: Dangerous activities // that might throw A, B, or C } catch(A a 1) { // Handler for situation A } catch(B b 1) { // Handler for situation B } catch(C c 1) { // Handler for situation C } finally { // Activities that happen every time }

Example of the finally usage class Three. Exception extends Exception {} public class Finally.

Example of the finally usage class Three. Exception extends Exception {} public class Finally. Works { private static Test monitor = new Test(); static int count = 0; public static void main(String[] args) { while(true) { try { // Post-increment is zero first time: if(count++ == 0) throw new Three. Exception(); System. out. println("No exception"); } catch(Three. Exception e) { System. err. println("Three. Exception"); } finally { System. err. println("In finally clause"); if(count == 2) break; // out of "while" } } monitor. expect(new String[] { "Three. Exception", "In finally clause", "No exception", "In finally clause" }); } } ///: ~

Example of finally usage public class Switch { private boolean state = false; public

Example of finally usage public class Switch { private boolean state = false; public boolean read() { return state; } public void on() { state = true; } public void off() { state = false; } } public class On. Off. Exception 1 extends Exception {} public class On. Off. Exception 2 extends Exception {} public class On. Off. Switch { private static Switch sw = new Switch(); public static void f() throws On. Off. Exception 1, On. Off. Exception 2 {} public static void main(String[] args) { try { sw. on(); // Code that can throw exceptions. . . f(); sw. off(); } catch(On. Off. Exception 1 e) { System. err. println("On. Off. Exception 1"); sw. off(); } catch(On. Off. Exception 2 e) { System. err. println("On. Off. Exception 2"); sw. off(); } } public class With. Finally { static Switch sw = new Switch(); public static void main(String[] args) { try { sw. on(); // Code that can throw exceptions. . . On. Off. Switch. f(); } catch(On. Off. Exception 1 e) { System. err. println("On. Off. Exception 1"); } catch(On. Off. Exception 2 e) { System. err. println("On. Off. Exception 2"); } finally { sw. off(); } }

Exception restrictions ● When overidding a method (in an inheritance hierarchy), it can only

Exception restrictions ● When overidding a method (in an inheritance hierarchy), it can only throw exceptions that are specified in the base class version of the method class Baseball. Exception extends Exception {} class Foul extends Baseball. Exception {} class Strike extends Baseball. Exception {} class Storm. Exception extends Exception {} class Rained. Out extends Storm. Exception {} class Pop. Foul extends Foul {} abstract class Inning { public Inning() throws Baseball. Exception {} public void event() throws Baseball. Exception { // Doesn't actually have to throw anything } public abstract void at. Bat() throws Strike, Foul; public void walk() {} // Throws no checked exceptions } interface Storm { public void event() throws Rained. Out; public void rain. Hard() throws Rained. Out; }

Exception restrictions (cont. ) public static void main(String[] args) { try { public class

Exception restrictions (cont. ) public static void main(String[] args) { try { public class Stormy. Inning extends Inning implements Storm { Stormy. Inning si = new Stormy. Inning(); // OK to add new exceptions for constructors, but you si. at. Bat(); // must deal with the base constructor exceptions: } catch(Pop. Foul e) { public Stormy. Inning() System. err. println("Pop foul"); throws Rained. Out, Baseball. Exception {} } catch(Rained. Out e) { public Stormy. Inning(String s) System. err. println("Rained out"); throws Foul, Baseball. Exception {} } catch(Baseball. Exception e) { // Regular methods must conform to base class: System. err. println("Generic baseball exceptio //! void walk() throws Pop. Foul {} //Compile error } // Interface CANNOT add exceptions to existing // Strike not thrown in derived version. // methods from the base class: try { //! public void event() throws Rained. Out {} // What happens if you upcast? // If the method doesn't already exist in the Inning i = new Stormy. Inning(); // base class, the exception is OK: i. at. Bat(); public void rain. Hard() throws Rained. Out {} // You must catch the exceptions from the // You can choose to not throw any exceptions, // base-class version of the method: // even if the base version does: } catch(Strike e) { public void event() {} System. err. println("Strike"); // Overridden methods can throw inherited exceptions: } catch(Foul e) { public void at. Bat() throws Pop. Foul {} System. err. println("Foul"); } catch(Rained. Out e) { System. err. println("Rained out"); } catch(Baseball. Exception e) { System. err. println("Generic baseball exceptio }

Exceptions in constructors // Paying attention to exceptions in constructors. import com. bruceeckel. simpletest.

Exceptions in constructors // Paying attention to exceptions in constructors. import com. bruceeckel. simpletest. *; import java. io. *; class Input. File { private Buffered. Reader in; public Input. File(String fname) throws Exception { try { in = new Buffered. Reader(new File. Reader(fname)); // Other code that might throw exceptions } catch(File. Not. Found. Exception e) { System. err. println("Could not open " + fname); // Wasn't open, so don't close it throw e; } catch(Exception e) { // All other exceptions must close it try { in. close(); } } catch(IOException e 2) { System. err. println("in. close() unsuccessful"); } throw e; // Rethrow } finally { // Don't close it here!!! } } public String get. Line() { String s; try { s = in. read. Line(); } catch(IOException e) { throw new Runtime. Exception("read. Line() failed" } return s; } public void dispose() { try { in. close(); System. out. println("dispose() successful"); } catch(IOException e 2) { throw new Runtime. Exception("in. close() failed") } }

Exceptions in contstructors (cont. ) public class Cleanup { private static Test monitor =

Exceptions in contstructors (cont. ) public class Cleanup { private static Test monitor = new Test(); public static void main(String[] args) { try { Input. File in = new Input. File("Cleanup. java"); String s; int i = 1; while((s = in. get. Line()) != null) ; // Perform line-by-line processing here. . . in. dispose(); } catch(Exception e) { System. err. println("Caught Exception in main"); e. print. Stack. Trace(); } monitor. expect(new String[] { "dispose() successful" }); } }

Exception matching When an exception is thrown, the exception handling system looks through the

Exception matching When an exception is thrown, the exception handling system looks through the “nearest” handlers in the order they are written. When it finds a match, the exception is considered handled, and no further searching occurs. ●Matching an exception doesn’t require a perfect match. A derivedclass object will match a handler for the base class ● class Annoyance extends Exception {} class Sneeze extends Annoyance {} public class Human { private static Test monitor = new Test(); public static void main(String[] args) { try { throw new Sneeze(); } catch(Sneeze s) { System. err. println("Caught Sneeze"); } catch(Annoyance a) { System. err. println("Caught Annoyance"); } monitor. expect(new String[] { "Caught Sneeze" }); } try { throw new Sneeze(); } catch(Annoyance a) { System. err. println("Caught Annoyance"); } try { Compile error! throw new Sneeze(); } catch(Annoyance a) { System. err. println("Caught Annoyance"); } catch(Sneeze s) { System. err. println("Caught Sneeze"); }

Exception handling notes ● ● Don't catch an exception unless you know how to

Exception handling notes ● ● Don't catch an exception unless you know how to handle it How to do it? – One bad way: – A better way: Passing exceptions to the console try { //. . . to do something useful } catch(Obligatory. Exception e) {} public class Main. Exception { // Pass all exceptions to the console: public static void main(String[] args) throws Exception { // Open the file: File. Input. Stream file = new File. Input. Stream("Main. Exception. java"); // Use the file. . . // Close the file: file. close(); } } ///: ~

Exception handling notes (cont. ) – Convert checked to unchecked exception: try { //.

Exception handling notes (cont. ) – Convert checked to unchecked exception: try { //. . . to do something useful } catch(IDont. Know. What. To. Do. With. This. Checked. Exception e) { throw new Runtime. Exception(e); }