Exceptions • Defensive programming – Anticipating that something could go wrong Handling errors • Exception handling and throwing • Example: File processing Exception handling and throwing • Java: try-catch-finally, throw, throws Simple file processing • API: Exception, Stream, Reader/Writer • terminal input Error situations Example: Runtime error • Programmer errors • In class AddressBook: – Incorrect implementation public void removeDetails(String key) { – Inappropriate object request ContactDetails details = (ContactDetails) book.get(key); • Errors often arise from the environment: book.remove(details.getName()); ...} returns null when – incorrect URL entered trying to call method on key does not • Use: null results in Exception – network interruption exist in book AddressBook book = new AddressBook(); • File processing is particularly error prone: book.removeDetails("frederik"); – missing files • Result: – lack of appropriate permissions java.lang.NullPointerException • TØ first week: explore error situations at AddressBook.removeDetails(AddressBook.java:119) ... Defensive programming Defensive programming • Defense programming in client-server • Modified method in class AddressBook: interaction public void removeDetails(String key) { if(keyInUse(key)) { check argument – server assumes that clients are not well ContactDetails details = behaved (and potentially hostile) (ContactDetails) book.get(key); – E.g. server checks arguments to constructors book.remove(details.getName()); book.remove(details.getPhone()); and methods numberOfEntries--; • Significant overhead in implementation } } • Similar modifications to other methods
Server error reporting Returning a diagnostic did any errors arise? • How to report illegal arguments? public boolean removeDetails(String key) { – To the user? if(keyInUse(key)) { ContactDetails details = • is there a human user (ContactDetails) book.get(key); • can they solve the problem? book.remove(details.getName()); – To the client object book.remove(details.getPhone()); numberOfEntries--; • return a diagnostic value return true; • throw an exception } else { return false; } } Client responses Exception-throwing principles • Test the return value • A special language feature – Attempt recovery on error • No special return value needed – avoid program failure • Errors cannot be ignored in the client • Ignore the return value – The normal flow-of-control is interrupted – cannot be prevented • Specific recovery actions are encouraged – likely to lead to program failure • Exceptions are preferable Throwing an Exception The effect of an exception /** ... * @throws NullPointerException if the key is null • The throwing method finishes prematurely */ public ContactDetails getDetails(String key) { • No return value is returned if (key==null) { throw new NullPointerException( • Control does not return to the client's point "null key in getDetails"); of call } return (ContactDetails) book.get(key); – so the client cannot carry on regardless } • An exception object is constructed: • A client may 'catch' an exception – new ExceptionType("..."); • The exception object is thrown: – throw ... • Javadoc documentation: – @throws ExceptionType reason
The exception class hierarchy Exception categories • Checked exception – subclass of Exception – use for anticipated failures – where recovery may possible • Unchecked exception – subclass of RuntimeException – use for unanticipated failures – where recovery is unlikely Unchecked exceptions Argument checking public ContactDetails getDetails(String key) { • Use of these is 'unchecked' by the compiler if(key == null) { throw new NullPointerException( "null key in getDetails"); • Cause program termination if not caught } – this is normal practice if(key.trim().length() == 0) { – IllegalArgumentException is a typical throw new IllegalArgumentException( "Empty key passed to getDetails"); example } return (ContactDetails) book.get(key); } The throws clause Exception handling • Checked exceptions are meant to be • Methods throwing a checked exception caught must include a throws clause: • The compiler ensures that their use is tightly controlled public void saveToFile(String destinationFile) throws IOException { ... } – in both server and client • Used properly, failures may be recoverable
The try block The try block • Clients catching an exception must protect the call with a try block exception thrown from here try { addressbook.saveToFile(filename); tryAgain = false; try { control transfers to here } catch(IOException e) { Protect one or more statements here. System.out.println("Unable to save to " + filename); } catch(Exception e) { tryAgain = true; Report and recover from the exception here } } The finally clause Catching multiple exceptions try { ... try { ref.process(); Protect one or more statements here. ... } catch(Exception e) { } catch(EOFException e) { Report and recover from the exception here. // Take action on an end-of-file exception. } finally { ... } catch(FileNotFoundException e) { Perform any actions here common to whether or not // Take action on a file-not-found exception. an exception is thrown. ... } } The finally clause Defining new exceptions • Extend Exception or • A finally clause is executed even if a return statement is executed in the try or catch RuntimeException clauses • Define new types to give better diagnostic • An uncaught or propagated exception still information exits via the finally clause – include reporting and/recovery information
Example: new checked exception Error recovery • Clients should take note of error public class NoMatchingDetailsException extends Exception { notifications private String key; – check return values public NoMatchingDetailsException(String key) { this.key = key; } – don't 'ignore' exceptions public String getKey() • Include code to attempt recovery { return key; } – will often require a loop public String toString() { return "No details matching '" + key + "' were found."; } } Attempting recovery Text input-output // Try to save the address book. boolean successful = false; • Input-output is particularly error-prone int attempts = 0; do { – it involves interaction with the external try { addressbook.saveToFile(filename); environment successful = true; • The java.io package supports input- } catch(IOException e) { System.out.println("Unable to save to " + filename); output attempts++; if(attempts < MAX_ATTEMPTS) { • java.io.IOException is a checked filename = an alternative file name ; } exception } } while(!successful && attempts < MAX_ATTEMPTS); if(!successful) { Report the problem and give up; } Readers, writers, streams Text output • Use the FileWriter class • Readers and writers deal with textual input – based around the char type – open a file – write to the file • Streams deal with binary data – close the file – based around the byte type • Failure at any point results in an • The address-book-io project illustrates IOException . textual IO
Text output Text input try { • Use the FileReader class FileWriter writer = new FileWriter(" name of file "); • Augment with Scanner for line-based input while( there is more text to write ) { try { ... Scanner in = new Scanner( writer.write( next piece of text ); new FileReader(" name of file ")); ... while(in.hasNextLine()) { } String line = in.nextLine(); writer.close(); do something with line } catch(IOException e) { } something went wrong with accessing the file in.close(); } } catch(FileNotFoundException e) { the specified file could not be found } • IOExceptions from FileReader “swallowed” by Scanner User input from terminal window Two ways to store data • Similar to reading from a text file • Text format – construct a Scanner from System.in – human-readable form – no closing needed – sequence of characters Scanner in = new Scanner(System.in); • integer 12345 stored as "1" "2" "3" "4" "5" System.out.println("type a line of input:"); – use Reader and Writer (and their subclasses) String input = in.nextLine(); do something with input • Binary format – more compact and efficient • integer 12345 stored as 00 00 48 57 (12345 = 48*256+57) – Use InputStream and OutputStream (and their subclasses) • Writing object to file: Object streams BankAccount b1 = ...; ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("accounts.dat")); • ObjectOutputStream class can save entire out.writeObject(b1); objects to disk • Reading object from file: ObjectInputStream in = new ObjectInputStream(new • ObjectInputStream class can read objects FileInputStream("accounts.dat"); back in from disk BankAccount b2 = (BankAccount) in.readObject(); • Objects are saved in binary format (and readObject may throw a (checked) ClassNotFoundException streams are used) • Objects that are written to a file must be instances of a class implementing the Serializable interface: • similar to text files: public class BankAccount implements Serializable {...} – open, read/write, close Serializable interface has no methods
Recommend
More recommend