Exception Handling in Java

Download Report

Transcript Exception Handling in Java

Understanding Java Exceptions
Outline
What exceptions are for
What exceptions are NOT for
Catching & Throwing exceptions
Exception Specifications
Standard Java Exceptions
Exceptions and Polymorphism
The finally clause
Resource Management
Uncaught Exceptions
What Exceptions are For
To handle Bad Things
I/O errors, other runtime errors
 when a function fails to fulfill its specification
 so you can restore program stability (or exit
gracefully)

What Exceptions are For
~ continued ~
To force you to handle Bad Things
because return codes can be tedious
 and sometimes you’re lazy

Example
File I/O
public FileReader(String fileName)
throws FileNotFoundException
public void close() throws IOException
import java.io.*;
class OpenFile
{
public static void main(String[] args)
{
if (args.length > 0)
{
try
{
// Open a file:
FileReader f =
new FileReader(args[0]);
System.out.println(args[0]
+ " opened");
f.close();
}
catch (IOException x)
{
System.out.println(x);
}
}
}
}
What Exceptions are For
~ continued ~
To signal errors from constructors

because constructors have no return value
What Exceptions are NOT For
NOT For Alternate Returns:

e.g., when end-of-file is reached:
while ((s = f.readLine()) != null) …
Exceptions are only for the exceptional!
Catching Exceptions
Wrap code to be checked in a try-block

checking occurs all the way down the execution
stack
try-blocks can be nested

control resumes at most enclosed matching
handler
Catching Exceptions
~ continued ~
Place one or more catch-clauses after tryblock
runtime system looks back up the call stack for
a matching handler
 subclass types match superclass types



handlers are checked in the order they appear


catching Exception catches everything (almost)
place most derived types first!
execution resumes after last handler

if you let it (could branch or throw)
Throwing Exceptions
Must throw objects derived (ultimately) from
Throwable
Usually derive from java.lang.Exception
The class name is the most important attribute of
an exception
Can optionally include a message

Provide two constructors:


MyException( )
MyException(String s)
Throwing Exceptions
~ continued ~
Control is passed up the execution stack to a
matching handler
Various methods exist for processing
exceptions:
getMessage( )
 toString( )
(class name + message)
 printStackTrace( )

Throwing Exceptions
~ continued ~
Functions must “advertise” their exceptions

every function must specify the “checked”
exceptions it (or its callees!) may throw
Callers must do one of two things:
handle your exceptions with try-catch, or
 advertise your exceptions along with theirs

Sample Program
FixedStack
implements a stack with an array of Object
 various methods throw exceptions
 class StackException

StackTest

must handle StackExceptions
class StackException extends Exception
{
StackException()
{}
StackException(String msg)
{
super(msg);
}
}
class FixedStack
{
private int capacity;
private int size;
private Object[] data;
public FixedStack(int cap)
{
data = new Object[cap];
capacity = cap;
size = 0;
}
public void push(Object o)
throws StackException
{
if (size == capacity)
throw new StackException("overflow");
data[size++] = o;
}
public Object pop()
throws StackException
{
if (size <= 0)
throw new StackException("underflow");
return data[--size];
}
public Object top()
throws StackException
{
if (size <= 0)
throw new StackException("underflow");
return data[size-1];
}
public int size()
{
return this.size;
}
}
class StackTest
{
public static void main(String[] args)
{
FixedStack s = new FixedStack(3);
doTest(s);
}
public static void doTest(FixedStack s)
{
try
{
System.out.println("Initial size = "
+ s.size());
s.push("one");
s.push(new Integer(2));
s.push(new Float(3.0));
s.push("one too many");
}
catch(StackException x)
{
System.out.println(x);
}
// error!
try
{
System.out.println("Top: " + s.top());
System.out.println("Popping...");
while (s.size() > 0)
System.out.println(s.pop());
}
}
}
catch(StackException x)
{
throw new InternalError(x.toString());
}
/* Output:
Initial size = 0
StackException: overflow
Top: 3.0
Popping...
3.0
2
one
*/
Using printStackTrace( )
catch(StackException x)
{
x.printStackTrace(System.out);
}
…
StackException: overflow
at FixedStack.push(FixedStack.java:18)
at StackTest.doTest(StackTest.java, Compiled Code)
at StackTest.main(StackTest.java:6)
Standard Java Exceptions
Throwable
Exception
RuntimeException
Error
IOException
...
Class java.lang.Exception
The one you usually derive from
“Checked Exceptions”
specifications checked at compile time
 you must either catch or advertise these
 Used for recoverable errors


Not programmer errors
java.lang.Exception Subclasses
~ sample ~
AWTException
ClassNotFoundException
CloneNotSupportedException
IOException
NoSuchFieldException
Class java.lang.Error
For JVM Failures and other Weird Things

let program terminate
InternalError is one of these
Don’t catch them

you don’t know what to do!
These are “unchecked exceptions”

not required to advertise
java.lang.Error Subclasses
AWTError
LinkageError

…
ThreadDeath
VirtualMachineError

InternalError, OutOfMemoryError,
StackOverflowError, UnknownError
Class java.lang.RuntimeException
Stupid Name!

Same as logic_error in C++
Program logic errors
e.g., bad cast, using a null handle, array index
violation, etc.
 Shouldn’t happen!



fixed during testing
Similar in spirit to C’s assert( ) macro

mainly for debugging
These are called “unchecked exceptions”
java.lang.RuntimeException
Subclasses (sample)
ArithmeticException (e.g., divide by 0)
ArrayStoreException
ClassCastException
IllegalArgumentException
IndexOutOfBoundsException
NullPointerException
UnsupportedOperationException
Principle
“Use checked exceptions for recoverable
conditions and run-time exceptions for
programming errors” (Bloch, Effective
Java)
“Fixing” FixedStack
StackException should be a runtime
exception
Then the “throws” specifications aren’t
needed
class StackException extends RuntimeException
{
StackException()
{}
StackException(String msg)
{
super(msg);
}
}
• Then remove all “throws” specifications from FixedStack
Exceptions and Inheritance
~ Subclass Overrides ~
Methods overridden in subclasses must
maintain the parent method’s contract
substitutability
 cannot add exceptions to specification
 can omit, however
 can throw subclasses of parent’s exceptions

// Relaxing the Exception Specification
class Parent
{
public void f() throws Exception
{}
}
class Child extends Parent
{
public void f()
// OK!
{}
}
class Override
{
public static void main(String[] args)
{
Child c = new Child();
c.f();
}
}
// Throwing a Subclass Exception
class MyException extends Exception {}
class AnotherException extends MyException {}
class Parent {
public void f() throws MyException
{}
}
class Child extends Parent {
public void f() throws AnotherException
{}
}
class Override {
public static void main(String[] args)
throws AnotherException
{
Child c = new Child();
c.f();
}
}
Exception-handling Syntax
~ The Whole Picture ~
try
{
// normal code (conditionally executes)
}
catch (ExceptionType1 x)
{
// handle ExceptionType1 error
}
…
catch (ExceptionTypeN x)
{
// handle ExceptionTypeN error
}
finally
{
// invariant code ("always" executes)
}
The finally Clause
For code that must ALWAYS run
No matter what!
 Even if a return or break occurs first
 Exception: System.exit( )

Placed after handlers (if they exist)

try-block must either have a handler or a
finally-block
class FinallyTest
{
public static void f()
throws Exception
{
try
{
// return;
// System.exit(0);
// throw new Exception();
//
//
//
//
0
1
2
3a
}
catch (Exception x)
{
// throw new Exception();
// 3b
}
finally
{
System.out.println("finally!");
}
System.out.println("last statement");
}
public static void main(String[] args)
{
try
{
f();
}
catch(Exception x)
{}
}
}
Program Output
0:
finally!
last statement
1:
finally!
2:
(no output)
3a:
same as 0:
3a + 3b:
compiler error (last statement not reachable)
Managing Resources
Other than memory

files, connections, etc.
Need to deallocate, even if exceptions occur
Use finally
UPDATE: As of Java 7, you can use the
try-with-resources statement. See Core Java
Ch. 11, pp. 644-645 (9th ed.)
import java.io.*;
class Manage
{
public static void f(String fname)
throws IOException
{
FileReader f = null; // must define outside try
try
{
f = new FileReader(fname);
System.out.println("File opened");
int c = f.read();
// read a byte
// ...
}
finally
{
if (f != null)
{
System.out.println("File closed");
f.close(); // beware lost exception!!!
}
}
}
public static void main(String[] args)
{
try
{
f(args[0]);
}
catch (Exception x)
{
System.out.println(x);
}
}
}
Program Output
If no file name given (args.length == 0):
java.lang.ArrayIndexOutOfBoundsException: 0
If file doesn’t exist:
java.io.FileNotFoundException: <file name>
If file opened successfully:
file opened
file closed
When to Handle Exceptions
Note: Manage.f( ) didn’t catch anything

wouldn’t know what to do if it did!
You often let exceptions pass up the call
stack
Or you can re-throw in a catch
throw x; // in a handler where x was caught
 or re-throw a new type of exception

Exception Etiquette
Don’t catch what you can’t (at least
partially) handle

re-throw if only partially handled (“catch &
release”: if you’re not going to eat it, throw it
back!)
Don’t catch & ignore

catch (Exception x){} // disables exceptions!
How Exceptions Work
When an exception is thrown execution backtracks
up the runtime stack (list of active function
invocations)
Each stack frame contains information regarding
local handlers, if any

Otherwise, execution returns up to the next caller,
looking for a suitable catch
What happens if there isn’t a matching catch?
Uncaught Exceptions
What if there is no handler for an
exception?
The thread dies!

exceptions belong to a thread (stack-specific)