CS4723 Software Validation and Quality Assurance Lecture 15 Exception Handling.
-
Upload
alan-collins -
Category
Documents
-
view
220 -
download
0
Transcript of CS4723 Software Validation and Quality Assurance Lecture 15 Exception Handling.
CS4723Software
Validation and Quality Assurance
Lecture 15Exception Handling
2
We have talked about approaches to remove bugs Testing
Static Detection
Verification
Review
Approaches to avoid errors at runtime Errors Handling
Redundant component
Introduction
Users will use our programs in unexpected ways.
Due to design errors, coding errors or environmental changes, our programs may fail in unexpected ways during execution
We do not want unexpected errors in a component to fail the whole software
Errors and Error Handling
Some typical causes of errors: Memory errors (i.e. memory incorrectly
allocated, memory leaks, “null pointer”) File system errors (i.e. disk is full, disk has
been removed) Network errors (i.e. network is down, URL
does not exist) Calculation errors (i.e. divide by 0)
Errors and Error Handling
More typical causes of errors: Array index errors (i.e. accessing element –
1) Conversion errors (i.e. convert ‘q’ to a
number)
Errors and Error Handling
Traditional Error Handling Every method returns a flag indicating either
success, failure, or some error condition The calling method checks the return flag and takes
appropriate action.
Programmer must remember to always check the return value and take appropriate action.
This requires much code (methods are harder to read)
Errors and Error Handling
Traditional Error Handling C language use this method for almost all librar
y functions (i.e. fopen() returns a valid file or else null)
Command line commands, return 0 for success and other values for different errors
Errors and Error Handling
Traditional Error Handling Create a global error handling routine Use some form of “jump” instruction to call this routin
e when an error occurs
“jump” instruction (GoTo) are discouraged. Once you jump to the error routine, you cannot return a
nd must (probably) exit the program.
Errors and Error Handling
Traditional Error Handling Many older programming texts (C,
FORTRAN) recommended this method to programmers.
Those who use this method will frequently adapt it to new languages (C++, Java).
Example of Traditional Error Handling
struct lnode *insert(char *data, int len, struct lnode *list) { struct lnode *p, *q;
p = (struct lnode *)malloc(sizeof(struct lnode)); if ( NULL == p ) { return NULL; }
p->str = (char *)malloc(sizeof(char)*len); if ( NULL == p->str ) { // free node before returning. free ( p ); return NULL; }
... return list; \\success}
Example of Traditional Error Handling
struct lnode *insert(...) { p = (struct lnode *)malloc(sizeof(struct lnode)); if ( NULL == p ) { goto out; } p->str = (char *)malloc(sizeof(char)*len); if ( NULL == p->str ) { goto out_free_p; } ... return list; //success
out_free_p: free(p);out: return NULL;}
Errors and Error Handling
Exceptions – a better error handling Exceptions are a mechanism that provides the best
of both worlds.
Exceptions act similar to method return flags in that any method may raise an exception
Exceptions act like global error methods in that exceptions are handled at many levels in a program, locally and/or globally
Exceptions
What are they? An exception is a representation of an error
condition or a situation that is not the expected result of a method.
Exceptions are built into the Java language and are available to all program code.
Exceptions isolate the code that deals with the error condition from regular program logic.
Types of Exceptions
Exceptions fall into two categories: Checked Exceptions Unchecked Exceptions
Checked Exceptions
Inherited from the Java class Exception, but not RuntimeException
Represent exceptions that are considered “non fatal” to program execution
Checked exceptions must be handled in your code, or passed to parent methods.
Checked Exceptions
Compiler enforces catch-or-declare requirement
Compiler checks each method call and method declaration Determines whether method throws checked
exceptions. If so, the compiler ensures checked exception
caught or declared in throws clause. If not caught or declared, compiler error occurs.
Unchecked Exceptions
Represent error conditions that are considered “fatal” to program execution.
You do not have to do anything with an unchecked exception.
Your program will terminate with an appropriate error message.
Unchecked Exceptions
Inherit from class RuntimeException or class Error
Compiler does not check code to see if exception caught or declared
Can typically be prevented by proper coding
Examples
Checked exceptions File not found Number format conversion
Unchecked exceptions Null pointer Array index out of bounds
Exceptions
How to handle exceptions? Exception handling is accomplished through
the “try – catch” mechanism, or by a “throws” clause
Try-catch: Handle the exception yourself
Throws: Pass the exception “up the chain” (to a parent method).
TerminologyThrown exception – an exception that has
occurred
Stack trace Name of the exception in a descriptive message
that indicates the problem
Complete method-call stack
Terminology
Throw point – initial point at which the exception occurs, top row of call chain
FileOutputStream fos;ObjectOutputStream oos;try { fos = new FileOutputStream(file); //potential throw point oos = new ObjectOutputStream(fos); oos.writeObject(shapes); //potential throw point} catch (FileNotFoundException ex) { // complain to user} catch (IOException ex) { // notify user} finally { if (oos != null) oos.close(); if (fos != null) fos.close();}
Catch Clause
The code in the catch clause is executed when an exception is caught
An exception will terminate at the catch clause
Only the catch clause catching the exception will be executed
Throw and throws Clause
Throw statement: throw an exception, can be caught in the method or thrown to the parent method
Throws clause: appears after method’s parameter list and
before the method’s body
Contains a comma-separated list of exceptions
Finally Block
Consists of finally keyword followed by a block of code enclosed in curly braces
Optional in a try statement
If present, is placed after the last catch block
Finally Block
Executes whether or not an exception is thrown in the corresponding try block or any of its corresponding catch blocks
Will not execute if the application exits early from a try block via method System.exit
Typically contains resource-release code
Contrast: Execution Models
Termination model program control does not return to the
throw point try block has expired; Flow of control proceeds to the first
statement after the last catch blockResumption model
program control resumes just after throw point
Termination Model is used in most programming languages, e.g. Java
Control Flow in the example
FileOutputStream fos;ObjectOutputStream oos;try { fos = new FileOutputStream(file); oos = new ObjectOutputStream(fos); oos.writeObject(shapes); } catch (FileNotFoundException ex) { // complain to user} catch (IOException ex) { // notify user} finally { if (oos != null) oos.close(); if (fos != null) fos.close();}
More complex: control flow
FileOutputStream fos;ObjectOutputStream oos;try { fos = new FileOutputStream(file); oos = new ObjectOutputStream(fos); oos.writeObject(shapes); } catch (FileNotFoundException ex) { //complaint to user throw ex;} catch (IOException ex) { // notify user} finally { if (oos != null) oos.close(); if (fos != null) fos.close();}
Creating Custom Exception Classes
Use the exception classes in the API whenever possible.
Create custom exception classes if the predefined classes are not sufficient.
Declare custom exception classes by extending Exception or a subclass of Exception.
Pros and Cons of Exceptions
Pros
Separates error-handling code
making programs easier to read and to modify
Cons
Requires more time and resources
instantiating a new exception object
rolling back the call stack
propagating the errors to the calling methods
Write good exception handlings
General Principles
Not to many exception handling
If you want the exception to be processed by its caller, you should create an exception object and throw it.
If you can handle the exception in the method where it occurs, there is no need to throw it
Typically, throw and catch should not be in one method…
Never use exception handling for normal logic
You should just handle it with ifs
Example: what does this do?
void search( TreeNode node, Object data ) throws ResultException {
if (node.data.equals( data )) throw new ResultException( node ); else { search( node.leftChild, data ); search( node.rightChild, data ); }}
Example: what does this do?
try { for (int i = 0; /*wot no test?*/ ; i++) array[i]++;} catch (ArrayIndexOutOfBoundsException e) {
}
Example: throw or handle locally?
try{ _map.put(myKey, myValue);} catch(NullPointerException e){ _map = new HashMap<String, String>(); _map.put(myKey, myValue);}
if(_map == null){ _map = new HashMap<String, String>();}_map.put(myKey, myValue);
Example: throw or handle locally?
public put (Hashtable _map, key, value) throws …{ if(_map == null){ throw new NullHashtableException("..."); } …}
Catch or Throws? This is a question
If you do not know what to do, “Throws” is usually better than “catch”…
Reveal errors
Do not need to worry about the handling
When I should catch an exception?
I am pretty sure this exception does not fail the system
I have all the information of handling at this level
I want to add some info and re-throw
Example: good catch?
public void onClick(Event e){ String path = pathInput.getValue(); try{ FileOutputStream out = new FileOutputStream(path); … }catch(FileNotFoundException e){ JOptionPane.showMessagebox(path + " is not a valid path."); }}
Yes!
Example: good catch?
public void open(String path){ try{ FileOutputStream out = new FileOutputStream(path); … }catch(FileNotFoundException e){ e.printStackTrace(); }}
No!
General Principle
Throw early, Catch late
Why?boolean res = checkPositive(alist);if(!res){ throw new FooException("...");}boolean checkPositive(List alist{ for(Integer i : alist){ if(i < 0){ return false; } } return true;}
Throw as early as you know it!
General Principle
Catch late
public Integer tryParse(String text) { toConvert = reformat(text); try { int val = Integer.parseInt(toConvert); } catch (NumberFormatException e) { ...//what to do? }}
General Principle
Catch late
public List<Integer> convert(List<String> list) { List<Integer> ret = new ArrayList<Integer>(); for (String str : list){ try{ int val = tryParse(str); }catch(NumberFormatException e){ … // what to do? } ret.add(new Integer(val)); }}
General Principle
Catch late
public int sum(String line) { List<String> strList = new ArrayList<String>() for(String str : line.split()){ strList.add(str); } try{ List<Integer> nums = convert(strList); }catch(NumberFormatException e){ … //what to do? } return sum (nums);}
General Principle
Catch late
public void showSum (List<String> lines) { for (String line : lines){ show(sum(line)); }}
General Principle
Catch late
public void showSum (String path) { BufferedReader in = new BufferedReader(new FileReader(path)); List<String> lines = new ArrayList<String>(); for (String line = in.readLine(); line!=null; line = in.readLine()){ lines.add(line); } showSum(lines);}
What to put in the try clause?
We are using termination model
Therefore:
Put into try clause: all statements that cannot be executed normally if the exception is thrown
Do not put into try clause: all statements that can still be executed normally when the exception is thrown
Example
public void statement(String usr, String profile){ statement = statment + ... try{ FileInputStream out = new FileInputStream(profile); statement = statement + out.read(...); }catch(IOException e){ System.err.print("...") statement = statement + Statement.DefaultProfile; } statement = statement + ... ...}
Try clause and loop
Put the try clause (as well as catch) inside the loop if you want the loop to continue
Put the try clause (as well as catch) surrounding the loop if you want the loop to break
Example: loop
for(String path: list){ try{ FileInputStream out = new FileInputStream(path); dataMap.put(path, out.read(...)) }catch(IOException e){ System.err.print("...") }}
What exceptions to catch
The first catch clause will try to catch the exception first
Never catch Error and Throwable You are not able to handle them because they are JV
M errors
Never just catch Exception
} catch (FileNotFoundException ex) { //complaint to user throw ex;} catch (IOException ex) { // notify user
What to put into the catch clause?
Recover from the error
Error logs or user notification
Do not write an empty catch clause
Re-throw, why?
Example: why re-throw?
... try { fetchDescriptor(target, descFile); } catch (IOException ex) { Logger.log("Exception while fetching descriptor for " + target); throw ex; }
Add more information:
Example: why re-throw?
catch (SqlException ex){ switch (ex.Number) { case 18456: throw new InvalidDatabaseConnectionException(“…", ex); case 547: throw new CouldNotDeleteException(“…", ex); default: throw new UnexpectedDatabaseErrorException(“…", ex); } }
Handle different errors:
When re-throw, be careful!!
Reserve the stack trace!
try { // do work } catch (Exception t) { throw new ServletException("Error: " + t.getMessage()); }
Lose the stack trace!
When re-throw, be careful!!
try { // do work } catch (Throwable t) { // do something throw new ServletException("Error: " + t.getMessage(), t); }
try { // do work } catch (Throwable t) { // do something throw t;}
Both correct
What to put into finally
Do not forget the finally clause when your code involves elements below: Unlock thread locks Release resources
Database connections Network connections Files Readers and Writers
Sometimes finally is required when you throws
Example
public output(String file) throws IOException{ FileOutputStream fos; ObjectOutputStream oos; try { fos = new FileOutputStream(file); oos = new ObjectOutputStream(fos); oos.writeObject(shapes); } finally { if (oos != null) oos.close(); if (fos != null) fos.close(); }}
What to throw Do not throw an object of Exception class
Hard to identify from others
Do not throw too many checked exceptions Checked exceptions are used when the exceptions
are not fatal
You can wrap a checked exception as a runtime exception and re-throw it…
You can also wrap it back when you want to handle it
Wrapping exceptions
EX
EX
EX
EX
EX
EXEX
EX
EX
EX
EX
EX
EX
EX
EX
EX
EX
EX
EX
EX
EX
EX
EX
EX
EX
Service Level Logic Level UI Level
Wrapping exceptions
EX
EX
EX
EX
EX
EX
EX
EX
EX
EX
EX
Service Level Logic Level UI Level
Example: Exception wrapping
try{ ...}catch(IOException e){ throw new IORuntimeException("...", e);}
try{ ...}catch(IORuntimeException e){ throw new IOException("...", e);}
UI Level:
Very Deep Level:
Define your own exception Try to reuse existing exceptions
Easier for other people to understand
Never directly use Exception, RuntimeException, Error, Throwable, …
Do not define too many types of exceptions, especially checked ones
Put all information to debug
Hierarchy of Exceptions
Define your own exception
Consider using error code (enum) to differentiate exceptions
Use internationalized strings if you have public exceptions in a released library
Add dynamic fields to the exception
Example: enum error codepublic enum PaymentCode implements ErrorCode { SERVICE_TIMEOUT(101), CREDIT_CARD_EXPIRED(102), AMOUNT_TOO_HIGH(103), INSUFFICIENT_FUNDS(104);}
} catch (CreditCardException e) { if (e.getErrorCode() == PaymentCode.CREDIT_CARD_EXPIRED){ ... }}
Example: internationalized strings
public static String getUserText(ErrorCode errorCode) { if (errorCode == null) { return null; } String key = errorCode.getClass().getSimpleName() + "__" + errorCode; ResourceBundle bundle = ResourceBundle.getBundle(“…"); return bundle.getString(key); }
Example: dynamic fields
catch (IOException ex) { Logger.log("Exception while fetching descriptor for " + target); throw ex; } public FecthException{ private String target; public void setTarget(){…}}public RuntimeIOException{ private Hashtable<String, String> propTable = …; public void setProperty(String key, String value){ propTable.put(key, value) }}
Review of Exception handling
Types of exceptions Control flow of exceptions Pros and Cons of exceptions How to write good exceptions
Try What to catch? Catch Finally Throw Custom Exceptions
69
A review of the contents covered by the final exam
* : will be covered by the final exam Other contents listed: may be covered
by the final exam Contents not listed: will not be covered
by the final exam
70
Final Exam
Account for 40% of the grade
100 points in total
66% multiple choice
34% questions and answer
71
Introduction to software quality
Aspects of software quality Approaches to remove bugs*
Testing
Static Detection
Verification
Review
72
General Principles of Testing
Basic Concepts* Test case, test oracle, test suite, test driver,
test script, test coverage
Boundary value testing* Equivalent classes*
73
Unit Testing
Unit testing framework* State machine of JUnit
Find errors (incorrect way of using JUnit, low quality assertions, incomplete tear down, …) in test code
Handle Dependencies Dependency injection
Reduce dependency
Test Double
74
Unit Testing (cont.)
Test Doubles Difference between types of doubles*
Dummies
Stubs : Configurable Stubs
Fake Objects
Mocks*
Concepts, reason for using mocks
Write test mocks with easymock
75
Higher level Testing
Pros and Cons of different integration strategies* Big bang, bottom-up, top-down
Environment issues to be considered in system testing
Difference between Event-based and Screen-based GUI testing*
76
Test Coverage
Code coverage* Calculate statement/branch/data flow/path
coverage of given code and input
Know about code coverage status in practice
Input Combination Coverage* Combination width
Calculate input combination coverage given model, inputs and width
Approach to extract model from inputs of non-enumerated types
77
Test Coverage (cont.)
Mutation coverage* Calculate mutation score given mutants and
inputs
Know about equivalent mutants
78
Regression Testing
How to calculate APFD based on faults and a sequence of test cases*
How to do coverage based test prioritization (Total & Additional Strategy)*
Concept of data / control dependency
Find out backward slice of a given variable at a certain line of code
Pros & Cons of record and replay*
79
Non-Functional Testing
Concept of stress testing, soak testing and spike testing*
The concept of buffer overflow, stack status when buffer overflow happens
How to provide inputs to result in an SQL injection or OS injection*
80
Automatic Test Case Generation
Know what are the major approaches to automatic test case generation*
How to perform adaptive random testing given an input range
81
Issue Tracking System
The major types of issues
The life cycle of an issue*
Major resolution of issues
82
Debugging
Concept of delta debugging*
Understand the process of delta debugging, given a number of inputs and the input set that will reveal bug*
Concept of statistical debugging
83
Static Bug Detection
Major types of specifications*
General specifications and relevant bugs when violated*
Know major approaches to verify against specifications
Know what are pattern-based bug detectors
84
Design review
Coupling, Cohesion, and Cyclomatic Complexity*
Concept of software refactoring
85
Code review
Know about proper coding styles at all levels
Find coding style problems in given code*
Know about proper commenting, and how to generate Javadoc
86
Defect Prediction
Know about process prediction model
Know about product prediction model
87
Exception Handling
Control flow of try-catch-finally block
Good Catch and Bad Catch*
Re-throw
Find errors in try-catch-finally code samples*