200 likes | 293 Views
Exceptions. CSE301 University of Sunderland Harry Erwin, PhD. Introduction. Java was originally intended for use in embedded systems that had to provide a high degree of reliability. This led to a decision to support Meyers’ concept of ‘design by contract’.
E N D
Exceptions CSE301 University of Sunderland Harry Erwin, PhD
Introduction • Java was originally intended for use in embedded systems that had to provide a high degree of reliability. This led to a decision to support Meyers’ concept of ‘design by contract’. • ‘Design by Contract’ originally meant that any class method must satisfy two rules: • There are only two ways a method call may terminate: either it fulfills its contract or it fails to fulfill it. • If a method fails to fulfill its contract, the current execution of the calling method also fails to fulfill its own contract. • The alternative return used when a method fails to fulfill its contract is called “throwing an exception”.
What is the Contract? • The following is currently what we mean by design by contract. • You must publicly specify the contract associated with each method. These are the preconditions that must hold when the method is called and the postconditions that it guarantees will be true when it returns successfully. • The method should first check that its preconditions are true. If they aren’t, it should throw an exception. • At completion, it should check that its postconditions are met, and if not, it should again throw an exception. • Then it may return normally. • The assert statement has been added to Java to aid in programming this.
Contracts and Classes and Interfaces • The public methods of a class and the methods of an interface (which must be public) have associated contracts. These should be documented in the code docs. In combination, these make up the contract of the class or interface. • Programmers write their code based on those contracts. • Don’t surprise them by violating the contract. • <humour>They’ll crucify you. Couldn’t happen to a more deserving programmer…</humour>
Design by Contract and the Liskov Substitution Principle (LSP) • Design by contract is closely related to the LSP (second semester theory topic). • The LSP says “Subclasses should be substitutable for their base classes.” • That means a method designed by a programmer knowing a base class’s contract must still function when a derived class is substituted for the base class. Subclasses must still meet the base class’s contract. • Note that interfaces have contracts, too. The same principle applies. • Test questions!
Precondition Errors • A precondition error is a coding error and should be identified in unit testing. The exception thrown should provide enough information to allow a programmer to isolate the problem. • If this type of error is detected during operational use, it usually indicates the system is not running correctly and should be shut down. So leave those exceptions in the code! • The exception thrown is usually ‘unchecked’, and the calling method need not be designed to handle it. Know how to define an unchecked exception. • Test questions!
Postcondition Errors • An error detected at the end of the method’s processing means that the method cannot meet its contract. The calling method must be notified, but not using a normal return. • Instead a ‘checked’ exception is thrown; one the calling method must be designed to handle, since these exceptions may sometimes occur during normal operations. Know how to define a checked exception. • A ‘throws’clause must list the checked exceptions. • Test questions!
Weak and Strong Design by Contract • Definitions… • The weak version of Design by Contract is that a method throwing an exception must leave the system in an operable state. This should be your default approach. • The strong version is that a method throwing an exception must leave the system in the state it was in prior to the point the method was called. • Use the strong approach in high-reliability systems, when you want to try more than one way of providing a function, or you need to interact with the user to handle the problem. • Test question!
Syntax: Exception Classes (TQ!) Throwable Root class of the hierarchy Exception Error Unrecoverable problems Runtime- Exception Your ‘checked’ exceptions Your ‘unchecked’ exceptions
Some Standard Runtime Exceptions You Can Use • ArithmeticException (e.g., divide by zero) • ArrayStoreException (invalid type) • ClassCastException (this is why you test instanceof prior to casting!) • IllegalArgumentException (you may use this if the precondition contract is violated) • IndexOutOfBoundsException (array, string, or vector) • NullPointerException (null reference encountered) • EmptyStackException (stack is empty) • NoSuchElementException (vector is empty)
Some Standard Checked Exceptions • IOException • EOFException • FileNotFoundException • MalformedURLException • ProtocolException • SocketException • UnknownHostException • UnknownServiceException
Defining, Creating, and Throwing an Exception • To define, extend Exception or RuntimeException • Example code: class MyException extends Exception { MyException(){super();} MyException(String s) {super(s);} } • Note that both constructors should be provided. • To create and throw an exception with a message: throw new MyException(“message”); • Test questions!
What Happens When an Exception is Thrown? • “When an exception is thrown, control is transferred from the code that caused the exception to the nearest dynamically-enclosing catch clause of a try statement that handles the exception.” (Gosling, Joy, and Steele, 1996). • Clear as mud? What that does is ‘unwind’ the call stack, moving control to the nearest applicable catch clause. • The finally blocks associated with each try statement in this process will be executed as the stack is unwound. These are used for mopping-up.
Syntax: Try, Catch and Finally • A statement is ‘dynamically enclosed’ if it is in a ‘try block’. The try block is a code block introduced by the keyword ‘try’. • A try block may be followed by one or more ‘catch clauses’. The first catch clause for which the exception thrown is an instance of the exception type of the clause will be executed. The catch clause may rethrow the exception or even throw another exception. • finally blocks are always executed whenever a try block or catch clause is executed. • Test questions!
Exception Handling Syntax try { some code that may throw } // try block catch (IOExceptioni) { code executed for an IOException may throw a new exception } catch (Exception e) { code executed for other exceptions note that the first match catches the Exception } finally {code always executed}
Code After a Try Block • This code is executed only as long as no exception has been thrown before it executes. • Often used to commit something successfully created or done in a try block: try{run some code that may throw} catch (Exception e) {return;} // exit for throw finally{code always executed} code executed if the try block doesn’t throw • Important test question!
Syntax: Throws • Used to notify the compiler that a method may throw an exception. retval foo(args) throws AnException; (or {code} in a method definition) • Necessary if a checked exception of that type (or a subtype) may be thrown out of the method. OK to document unchecked exceptions. • If some method you call can generate the checked exception and you don’t intend to catch it, you must indicate ‘throws’. If you will catch it, you don’t need to indicate ‘throws’. • The compiler enforces this! Test question!
Implementing Weak Design by Contract • finally clauses will need to be written to handle any problems that can cause the system to be inoperable. Otherwise you don’t have to do anything special. • This is probably not very different from how you program currently.
Implementing Strong Design by Contract • To provide strong design by contract, a method must separate operations that may throw from operations that modify the state of the system. • Put anything that may throw in a try block. Don’t change anything inside the try block; instead work with temporary objects to hold modified data. • ‘Commit’ your changes after the try block. This is where you change things using the temporaries that you prepared in the try block. • Note statements setting the values of primitive types and setting reference type objects equal to temporary objects never throw and can be used safely outside the try block. • Test question!
Final Comments • I generally write my main() function in the following way: public static void main(String[] args) { try { doProgram(); } // do the real work catch (Throwable e) { System.err.println(e.getMessage()); throw e; // rethrow the error } // catch any errors and print the msg return; // done } • I use this pattern to report whatever happened.