Upload
others
View
10
Download
0
Embed Size (px)
Citation preview
13: Error Handling with Exceptions
The basic philosophy of Java is that "badly formed code will not be run."
1
2
Error Handling in Java
C++/Java: Badly-formed code will not compile.
Java: Badly-formed code, if compiled, will not run.
Not all errors can be caught at compile time.
Run-time error handling is integrated into the core of the language and enforced by the compiler.
The standard libraries require the handling of exceptional conditions.
3
Program logic.
Errors like exceeding array bounds and division by zero can be prevented by the programmer.
Environmental conditions.
Loss of a network connection or a full disk can be anticipated but not prevented.
Sources of Problems
4
An exception is an object that signals an error condition and provides information about the error.
When an exception is generated, control is passed up the call stack until a specific handler is found.
Multiple handlers for different exceptions may be provided at multiple levels.
In Java, many exceptions cannot be ignored. This is enforced by the compiler.
Exceptions
5
An exceptional condition is a problem that prevents the continuation of the current method or scope.
To indicate such a condition, one throws an exception object:
Basic Exceptions
or
if (t == null) throw new NullPointerException();
If (t == null) throw new NullPointerException("t = null");
6
The Exception Class Hierarchy
Throwable
Error Exception
RuntimeException
CheckedExceptions
UncheckedExceptions
7
Throwable Methodspublic class Throwable implements Serializable { public Throwable(); public Throwable(String message); public Throwable(Throwable cause); public Throwable(String message, Throwable cause); public Throwable getCause(); public String getLocalizedMessage(); public String getMessage(); public StackTraceElement[] getStackTrace(); public void setStackTrace(StackTraceElement[] stackTrace); public Throwable fillInStackTrace(); public Throwable initCause(Throwable cause); public void printStackTrace(); public void printStackTrace(java.io.PrintStream s); public void printStackTrace(java.io.printWriter s); public String toString();}
8
Exception & RuntimeException
Methodspublic class Exception extends Throwable { public Exception(); public Exception(Throwable cause); public Exception(String message); public Exception(String message, Throwable cause);}
public class RuntimeException extends Exception { public RuntimeException(); public RuntimeException(Throwable cause); public RuntimeException(String message); public RuntimeException(String message, Throwable cause);}
9
Catching Exceptions
A thrown exception will cause immediate transfer from a try block to an appropriate catch clause.
try { /* Code that might generate exceptions */ }catch (Type1 e1) { /* Handle exceptions of Type1 */ }catch (Type2 e2) { /* Handle exceptions of Type2 */ }catch (Type3 e3) { /* Handle exceptions of Type3 */ }finally { /* Execute code that will always run */ }
10
The Exception Specification
Any exception thrown by a method (except for runtime exceptions) must be declared in a throws clause.
This is enforced by the compiler.
All checked exceptions will be caught somewhere.
11
Creating an Exception
Throwing MyException from f()MyException at FullConstructors.f(FullConstructors.java:10) at FullConstructors.main(FullConstructors.java:16)Throwing MyException from g()MyException: Originated in g() at FullConstructors.g(FullConstructors.java:13) at FullConstructors.main(FullConstructors.java:20)
12
Getting More Creative
class MyException2 extends Exception { private int x; public MyException2() {} public MyException2(String msg) { super(msg); } public MyException2(String msg, int x) { super(msg); this.x = x; } public int val() { return x; } public String getMessage() { return "Detail Message: " + x + " " + super.getMessage(); }}
13
Testing the Classpublic class ExtraFeatures { public static void f() throws MyException2 { print("Throwing MyException2 from f()"); throw new MyException2(); } public static void g() throws MyException2 { print("Throwing MyException2 from g()"); throw new MyException2("Originated in g()"); } public static void h() throws MyException2 { print("Throwing MyException2 from h()"); throw new MyException2("Originated in h()", 47); } public static void main(String[] args) { try { f(); } catch (MyException2 e) { e.printStackTrace(System.out); } try { g(); } catch (MyException2 e) { e.printStackTrace(System.out); } try { h(); } catch (MyException2 e) { e.printStackTrace(System.out); System.out.println("e.val() = " + e.val()); } }}
Throwing MyException2 from f()MyException2: Detail Message: 0 null at ExtraFeatures.f(ExtraFeatures.java:22) at ExtraFeatures.main(ExtraFeatures.java:34)Throwing MyException2 from g()MyException2: Detail Message: 0 Originated in g() at ExtraFeatures.g(ExtraFeatures.java:26) at ExtraFeatures.main(ExtraFeatures.java:39)Throwing MyException2 from h()MyException2: Detail Message: 47 Originated in h() at ExtraFeatures.h(ExtraFeatures.java:30) at ExtraFeatures.main(ExtraFeatures.java:44)e.val() = 47
14
RethrowingA caught exception may be partially handled and thrown again:
The rethrown exception goes to the next higher context. All of its contained information is preserved.
catch(Exception e) } System.err.println("An exception was thrown."); throw e; }
15
Installing a New Stack Tracepublic class Rethrowing { 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 Exception { try { f(); } catch (Exception e) { System.out.println("Inside g(),e.printStackTrace()"); e.printStackTrace(System.out); throw e; } } public static void h() throws Exception { try { f(); } catch (Exception e) { System.out.println("Inside h(),e.printStackTrace()"); e.printStackTrace(System.out); throw (Exception)e.fillInStackTrace(); } } public static void main(String[] args) { try { g(); } catch (Exception e) { System.out.println("main: printStackTrace()"); e.printStackTrace(System.out); } try { h(); } catch (Exception e) { System.out.println("main: printStackTrace()"); e.printStackTrace(System.out); } }}
originating the exception in f()Inside g(),e.printStackTrace()java.lang.Exception: thrown from f() at Rethrowing.f(Rethrowing.java:7) at Rethrowing.g(Rethrowing.java:11) at Rethrowing.main(Rethrowing.java:29)main: printStackTrace()java.lang.Exception: thrown from f() at Rethrowing.f(Rethrowing.java:7) at Rethrowing.g(Rethrowing.java:11) at Rethrowing.main(Rethrowing.java:29)originating the exception in f()Inside h(),e.printStackTrace()java.lang.Exception: thrown from f() at Rethrowing.f(Rethrowing.java:7) at Rethrowing.h(Rethrowing.java:20) at Rethrowing.main(Rethrowing.java:35)main: printStackTrace()java.lang.Exception: thrown from f() at Rethrowing.h(Rethrowing.java:24) at Rethrowing.main(Rethrowing.java:35)
16
Rethrowing a New Exceptionclass OneException extends Exception { public OneException(String s) { super(s); }}
class TwoException extends Exception { public TwoException(String s) { super(s); }}
public class RethrowNew { public static void f() throws OneException { System.out.println("originating the exception in f()"); throw new OneException("thrown from f()"); } public static void main(String[] args) { try { try { f(); } catch (OneException e) { System.out.println( "Caught in inner try, e.printStackTrace()"); e.printStackTrace(System.out); throw new TwoException("from inner try"); } } catch (TwoException e) { System.out.println( "Caught in outer try, e.printStackTrace()"); e.printStackTrace(System.out); } }}
originating the exception in f()Caught in inner try, e.printStackTrace()OneException: thrown from f() at RethrowNew.f(RethrowNew.java:15) at RethrowNew.main(RethrowNew.java:20)Caught in outer try, e.printStackTrace()TwoException: from inner try at RethrowNew.main(RethrowNew.java:25)
17
Cleanup With Finally
The finally clause provides a mechanism to take care of non-memory resources.
Anything that must always be done should be included in the finally clause.
The finally clause should not be used for operations that may not always be needed or appropriate.
18
Doesn’t Always Workpublic class Switch { private boolean state = false; public boolean read() { return state; } public void on() { state = true; print(this); } public void off() { state = false; print(this); } public String toString() { return state ? "on" : "off"; }}
public class OnOffSwitch { private static Switch sw = new Switch(); public static void f() throws OnOffException1, OnOffException2 {} public static void main(String[] args) { try { sw.on(); // Code that can throw exceptions... f(); sw.off(); } catch (OnOffException1 e) { System.out.println("OnOffException1"); sw.off(); } catch (OnOffException2 e) { System.out.println("OnOffException2"); sw.off(); } }}
19
Always Works
public class WithFinally { static Switch sw = new Switch(); public static void main(String[] args) { try { sw.on(); // Code that can throw exceptions... OnOffSwitch.f(); } catch (OnOffException1 e) { System.out.println("OnOffException1"); } catch (OnOffException2 e) { System.out.println("OnOffException2"); } finally { sw.off(); } }}
20
Inheritance Implications
Overridden methods may only throw exceptions specified in the base-class version.
Derived-class exceptions do not violate the rule.
The restriction does not apply to constructors.
Derived-class constructors must declare base-class exeptions in their exception specification.
21
If a constructor throws an exception proper cleanup may not occur.
Any sort of cleanup done in a finally clause should be executed conditionally and controlled by a flag.
Only perform this cleanup in finally if you’re forced to.
Constructors
22
Cleanup Examplepublic class InputFile { private BufferedReader in; public InputFile(String fname) throws Exception { try { in = new BufferedReader(new FileReader(fname)); /* Other code that might throw exceptions */} catch (FileNotFoundException e) { System.out.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 e2) { System.out.println("in.close() unsuccessful"); } throw e; /* Rethrow */ } finally { /* Don't close it here */} }
23
The Rest of the Class
public String getLine() { String s; try { s = in.readLine(); } catch (IOException e) { throw new RuntimeException("readLine() failed"); } return s; }
public void dispose() { try { in.close(); System.out.println("dispose() successful"); } catch (IOException e2) { throw new RuntimeException("in.close() failed"); } }}
24
Client Code
public class Cleanup { public static void main(String[] args) { try { InputFile in = new InputFile("Cleanup.java"); try { String s; int i = 1; while ((s = in.getLine()) != null) ; /* Perform line-by-line processing here... */ } catch (Exception e) { System.out.println("Caught Exception in main"); e.printStackTrace(System.out); } finally { in.dispose(); } } catch (Exception e) { System.out.println("InputFile construction failed"); } }}
25
Exception Matching...
Handlers are searched through in the order in which they were written.Derived-class exceptions match base-class handlers.The compiler will detect unreachable code.
26
...Exception Matchingclass Annoyance extends Exception {}
class Sneeze extends Annoyance {}
public class Human { public static void main(String[] args) { // Catch the exact type: try { throw new Sneeze(); } catch (Sneeze s) { System.out.println("Caught Sneeze"); } catch (Annoyance a) { System.out.println("Caught Annoyance"); } // Catch the base type: try { throw new Sneeze(); } catch (Annoyance a) { System.out.println("Caught Annoyance"); } }}
27
Avoiding the IssueExceptions are harmful if swallowed:
Or you can do nothing and get a stack trace:
try { /* ...to do something useful */ }catch(Exception e) {} // Gulp!
public class MainException { public static void main(String[] args) throws Exception { // Use the file... // Close the file: file.close(); }}
28
Converting an Exception
You can turn a checked exception into a runtime exception:
try { somethingUseful(); }catch(IDontKnowWhatToDoWithThisCheckedException e) { throw new RunTimeException(e); }
29
Overhead
Exceptions are free as long as they don’t get thrown.
Thrown exceptions are expensive.
Don’t use exceptions for normal flow of control.
Exceptions should only be used to handle abnormal conditions.
30
Handle an exception only if there is enough information in the current context to correct the error. If not, allow it to propigate upward.
Separated error handling from normal flow makes code more readable and maintainable.
Handle complete tasks, not single statements in a try block.
Resumption causes excessive coupling and is not available in C++/Java. Use loops to retry.
Guidelines
31
Use exceptions in constructors if something could go wrong: people assume construction succeeds.
If you catch an exception, do something with it; don’t stub it out.
Clean up using finally.
Guidelines
32
Exception handling in Java is enforced by the compiler:
they must be caught,exception specification must be provided.
Error handling is clean and straightforward:error handling is left to the client programmer,how the client handles the error is decoupled from the implementation,the implementer knows that errors will be handled.
If it seems like more work it’s because you’ve been ignoring errors.
Summary