exception handling
DESCRIPTION
Exception Handling. The finer details …. The exceptions mechanism. When an exception is generated, control is immediately transferred to one of three places: catch block finally block the calling method. Understanding this “ goto ” behavior is important for several reasons: - PowerPoint PPT PresentationTRANSCRIPT
The exceptions mechanismThe exceptions mechanism
• When an exception is generated, control is immediately
transferred to one of three places:
• catch block
• finally block
• the calling method
• Understanding this “goto” behavior is important for several
reasons:
• Maintaining objects’ state
• The code jumps from one place to another - logic gets
complicated.
The exceptions mechanismThe exceptions mechanism
• Consider the following example:
Class ExceptionTest {
public static void main(String[] args) {
ExceptionTest et = new ExceptionTest();
try {
Vector v = new Vector();
System.out.println(“calling m1()”);
et.m1();
System.out.println(“returning from call to m1()”);
}
catch (IOException e) {
System.out.println(“caught IOException in main()”);
}
} // End of main()
The exceptions mechanismThe exceptions mechanism
public void m1() throws IOException {
System.out.println(“entering m1()”);
try {
System.out.println(“calling m2()”);
m2();
System.out.println(“returning from call to m2()”);
System.out.println(“calling m3()”);
m3(true);
System.out.println(“returning from call to m2()”);
}
catch (IOException e) {
System.out.println(“caught IOException in m1()… rethrowing”);
throw e;
}
finally {
System.out.println(“in finally for m1()”);
}
} // End of m1()
The exceptions mechanismThe exceptions mechanism
public void m2() {
System.out.println(“entering m2()”);
try {
// perform some valid operation
}
catch (Exception e) {
System.out.println(“we will never get here”);
}
finally {
System.out.println(“in finally for m2()”);
}
} // End of m2()
The exceptions mechanismThe exceptions mechanism
public void m3(boolean generateException) throws IOException {
System.out.println(“entering m3()”);
try {
if (generateException)
throw new IOException();
}
finally {
System.out.println(“in finally for m3()”);
}
} // End of m3()
What will be the output of this program?
The exceptions mechanismThe exceptions mechanism
calling m1()
entering me1()
calling m2()
entering m2()
in finally for m2()
returning from call to m2()
calling m3()
entering m3() // We throw an exception here
in finally for m3()
caught IOException in m1()… rethrowing
in finally for m1()
caught IOException in main()
The exceptions mechanismThe exceptions mechanism
• A few notes about the flow of the program;
• If no exception is thrown, the catch block is never executed.
• If an exception is thrown, but no catch block exists, the
throw gets transferred to the calling method.
• A method that propagates an exception, must specify the
exception in the throws declaration.
• A finally block will always be executed, no matter what
happened in the try block.
• Because of the garbage collection, you don’t have to worry
about cleaning up objects memory.
Ignoring an exceptionIgnoring an exception
• When an exception is generated, what happens if you don’t
catch it?The thread on which the exception occurred will
terminate !!!• So, when an exception is generated, what can you do?
1) Catch the exception and handle it (it won’t propagate).
2) Catch the exception and rethrow it.
3) Catch the exception and throw a new one.
4) Do not catch it and let it propagate.
Options 2,3 and 4 require you to add the exception to the throws clause of your method.
• Option 1 stops the exception from propagating further.
• If you chose option 3, make sure the new exception contains
the relevant information from the original exception.
• Option 1 is often used in an ill-advised fashion to ignore the
exception:
Ignoring an exceptionIgnoring an exception
try {
// some code that generates an Exception
}
catch (Exception e) {
}
// code continues here
The exception was “eaten”
Ignoring an exceptionIgnoring an exception
• The danger here is that the code may fail later on.
• If you are not sure what to do with the exception in the early
stages of development, at minimum do something like the
following: try {
// some code that generates an Exception
}
catch (Exception e) {
System.out.println(e + “ was caught in method…”);
logReport(e);
}
// code continues here
Ignoring an exceptionIgnoring an exception
• Another useful approach is to use the printStackTrace method. try {
// some code that generates an Exception
}
catch (Exception e) {
System.out.println(e + “ was caught in method…”);
e.printStackTrace();
}
// code continues here
The best approach - do not put off the dirty work of exception and error handling.
Hiding an exceptionHiding an exception
• An exception is hidden when one is thrown from a catch or
finally block during the processing of a previously thrown
exception - option 3. try {
throw new Exception(“exception 1”);
}
catch (Exception e) {
throw new Exception(“exception 2”);
}
finally {
throw new Exception(“exception 3”);
}
Which exception is
thrown?
Hiding an exceptionHiding an exception
• A real life example:
try {
readFile();
}
catch (FileNotFoundException fne) {
// one way to handle the exception
}
catch (IOException ioe) {
// another way to handle it
}
Hiding an exceptionHiding an exception
public void readFile() throws FileNotFoundException, IOException {
BufferedReader br1, br2;
FileReader fr;
try {
fr = new FileReader(“data1.txt”); // FileNotFoundException
br1 = new BufferedReader(fr);
int i = br1.read(); // IOException
fr = new FileReader(“data2.txt”); // FileNotFoundException
br2 = new BufferedReader(fr);
int j = br2.read(); // IOException
}
finally {
if (br1 != null)
br1.close(); // IOException
if (br2 != null)
br2.close(); // IOException
}
}
A comprehensive throws clauseA comprehensive throws clause
• The throws clause is provided to alert callers of a method to the
checked exceptions it might generate.
• Consider the following example: class Exception1 extends Exception {}
class Exception2 extends Exception1 {}
class Exception3 extends Exception2 {}
class Lazy {
public void foo(int i) throws Exception1 {
if (i == 1)
throw new Exception1();
else if (i == 2)
throw new Exception2();
else if (i == 3)
throw new Exception3();
}
}
A comprehensive throws clauseA comprehensive throws clause
• Method foo() is declared to throw only one type of an exception
- Exception1.
• In reality, the method may throw one three exceptions.
• This code is perfectly legal as Exception2 and Exception3 are
derived from Exception1. This however has a drawback! try {
Lazy l = new Lazy();
l.foo(3);
}
catch (Exception1 e) {
// handle the exception
}
A comprehensive throws clauseA comprehensive throws clause
• If the user doesn’t have the source code, he will never know
about the other two exceptions.• When you write your functions, don’t be lazy
public void foo(int I) throws Exception1, Exception2, Exception3
Exceptions and overridingExceptions and overriding
• When you override a method, which exceptions types are you
allowed to throw, and which do you include in the throws clause?class Base {
public void foo() throws FileNotFoundException {
throw new FileNotFoundException();
}
}
Class Derived extends Base {
public void foo() throws IOException {
throw new IOException ();
}
}Compilation Error!!!
Exceptions and overridingExceptions and overriding
• When you override a method, the two methods must be
identical.
• What can you do in the overridden foo() method?
• Not throw any exception
• Throw a FileNotFoundException
• Throw an exception derived from FileNotFoundException
• When you override a method that does not throw an exception,
and add code to the overriding method that does, you must
catch that exception in the method.
• You are unable to propagate the exception outside the method.
Using finallyUsing finally
• The finally construct enables code to execute whether or not an
exception occurred.
• Using finally is a good practice to maintain the internal state of
object.
• Here is how you would write code without the use of finally:
Socket s = new Socket(“sol4”, 2783);
BufferedReader r = new BufferedReader(new InputStreamReader(s.getInputStream()));
try {
String text = r.readline();
}
catch (IOException e) {
s.close();
throw e;
}
s.close();
Using finallyUsing finally
• Using finally the code become more compact:
Socket s = new Socket(“sol4”, 2783);
BufferedReader r = new BufferedReader(new InputStreamReader(s.getInputStream()));
try {
String text = r.readline();
}
finally {
s.close();
}
Exiting the try blockExiting the try block
• The try/finally block is straightforward but has some behavior
that catches even the knowledgeable programmer off guard.
• There is no way to exit the try block without executing its finally
block. If the finally block exists, it always executes.*
• Code leaves a try block when any of the following occurs:
• An exception is thrown.
• The try block finishes normally.
• A return, break or continue statement is executed within it.
*You can always use System.exit(0), but on the other hand, unplugging
the computer during the try block will not execute it either.
Exceptions and performanceExceptions and performance
• Exceptions can have negative impact on the performance of your
code.
• Structuring your code correctly, can greater improve performance.
• There are two areas of exceptions that affect performance:
• The effect of throwing an exception.
• The effect of try/catch blocks in your code.• The act of throwing an exception is not free - Exceptions are
objects, and thus need to be created - throw new Exception().
• Creating objects takes time, so only throw exceptions when you
have to.
Exceptions and performanceExceptions and performance
• Placing exceptions inside loops can slow down the execution of
code as the following illustrates:
Public void m1(int size) {
int[] array = new int[size];
try {
for (int i=0; i<size; i++)
array[i] = i;
}
catch (Exception) {} // exception ignore on purpose.
}
Public void m2(int size) {
int[] array = new int[size];
for (int i=0; i<size; i++) {
try {
array[i] = i;
}
catch (Exception) {} // exception ignore on purpose.
}
}
Exceptions and performanceExceptions and performance
• m2 is approximately 20% slower than m1.
• The bytecode for m2 has more opcode executed in its loop.
Exceptions in constructorsExceptions in constructors
• Traditional error reporting from constructors can be problematic
because a constructor has no return value.
• Error reporting from constructors have typically been
accomplished via several techniques:
• Two stage construction.
• An internal flag.• These techniques lack in robustness – they rely on the user of the
class to remember to perform the two stage construction or to
check an internal flag.
• You avoid all this by throwing exceptions from your constructors.
Exceptions & Objects statesExceptions & Objects states
• Throwing an exception is easy.
• The hard part is to minimize the damage you cause by throwing it.• What is the purpose of throwing an exception ?
• Explicitly - to inform another part of the system about a
problem.
• Implicitly - to allow the system to potentially recover from the
problem and continue running smoothly. • Objects whose state was altered prior to the exception could be
referenced after the exception.
• What good is it to throw an exception if you leave objects in invalid
or undefined state?
Exceptions & Objects statesExceptions & Objects states
class MyList {}
class Foo {
private int numElements;
private MyList list;
public void add(Object o) throws Exception {
// …
numElements++;
if (list.maxElements() < numElements) {
// Reallocate list and copy elements - could throw an exception
}
list.addToList(o); // could throw an exception
}
}