exception handling 9-6-2013 - clarkson universityjsearlem/cs242/fa13/lectures/07.exceptions.pdfan...
TRANSCRIPT
Exception Handling
9-6-2013
Exception Handling Types of exceptions
Standard exceptions
Propagating vs. handling exceptions
HW#2 posted; due 9/23/2013
Reading assignment: EJ2, Chapter 9, Exceptions
Java allows every method an alternative exit path if it is unable to complete its task in the normal way.
In this situation, the method does NOT return a value; instead it creates & “throws” an exception object that encapsulates the error information and it exits immediately
Java’s exception handling system will search the call stack for an “exception handler” that can deal with this error
An exception is an object it contains information about the problem methods exist which retrieves this information
There are checked exceptions and unchecked exceptions
There are 2 ways of dealing with exceptions:
1.throwing exceptions (propagation):
the applications programmer decides what to do about the problem
2.handling exceptions (try/catch):
the class designer handles it internally
public class Magic {
public String castSpell(int n) { … }
} // end Magic
public class Lamp {
public void init() {
Magic m = new Magic();
String arg = m.castSpell(42);
}
} // end Lamp
public class Test {
public static void main(…) {
Lamp t = new Lamp();
t.init();
}
} // end Test 1. main() calls Lamp.init()
2.1 Lamp.init() calls Magic.castSpell()
3. Magic.castSpell() currently executing
0. main() calls constructor
2.0 calls constructor
main() Lamp.init() Magic.castSpell()
case 1: normal operation.
1. castSpell() returns a string to the point of call
case 2: exception occurs.
1. execution of castSpell() immediately terminates, a string is not returned, do not return to point of call;
2. search backwards through call stack until an appropriate exception handler is found; if none found, program terminates
currently executing
checked (meaning the compiler can check)
most application exceptions are checked
if you call a method which throws a checked exception, you MUST specify to the compiler how this will be handled:
either (1) propagate (or throw) it, or (2) handle the error at once (try/catch)
unchecked
subclasses of java.lang.RuntimeException or java.lang.Error (i.e. programming errors or system errors)
Object
Throwable
Exception Error
IOException RuntimeException
FileNotFoundException ArithmeticException
AssertionError
Standard
Exceptions
RuntimeException
ArithmeticException
NullPointerException
ClassCastException
Exception Standard
Exceptions
java.io.IOException
EOFException
FileNotFoundException
MalformedURLException
java.lang.Exception
Standard
Exceptions
/* Example: Want to write a method, readLine(), that reads in a line of text. Algorithm: have a loop that calls System.in.read() which reads in one character. */
public int read() throws IOException
Returns: the next byte of data, or -1 if the
end of the stream is reached.
Throws: IOException - if an I/O error occurs.
This is a checked exception, so the method readLine() must either handle the exception internally or “propagate” it externally
// Alternative 1: propagate the error // (let someone else in the call stack handle it)
public static String readLine() throws IOException
{ /* code to read in a line of text */ }
// Alternative 2: handle the error internally
public static String readLine() {
try {
/* code to read in a line of text */
} catch(IOException e) {
/* do something sensible about an I/O error */
} }
// Version 1: if error occurs, propagate the error // (loses partial line)
public static String readLine() throws IOException {
int ch; String r = ""; boolean done = false;
while(!done) {
ch = System.in.read();
if ((ch < 0) || (ch == '\n'))
done = true;
else
r = r + (char)ch;
}
return r;
}
if an error occurs in read(), the code for read will create a new exception object and throw it here; then readLine() will propagate (throw) the error to where it was called
// Test Version 1 of readLine()
import java.io.*;
public class TestVersion1 {
// Version 1: if error occurs, propagate the error
public static String readLine()
throws IOException
{ … }
public static void main(String[] args) {
System.out.print("Enter a line:");
System.out.println(readLine());
}
} compile error! why? unreported exception
// Test Version 1 of readLine(), take 2
import java.io.*;
public class TestVersion1 {
// Version 1: if error occurs, propagate the error
public static String readLine() throws IOException
{ … }
public static void main(String[] args) {
System.out.print("Enter a line:");
try {
System.out.println(readLine());
} catch(IOException e) {
System.err.println(e.getMessage()); }
}
}
// Version 2: if read() fails, return partial line
public static String readLine() {
int ch; String r = ""; boolean done = false;
while(!done) {
try {
ch = System.in.read();
if (ch < 0) || (char)ch == '\n')
done = true;
else
r = r + (char)ch;
} catch(IOException e) { done = true; }
}
return r;
}
// Test Version 2 of readLine()
import java.io.*;
public class TestVersion2 {
// Version 2: if error occurs, return partial line
public static String readLine()
{ … }
public static void main(String[] args) {
System.out.print("Enter a line:");
System.out.println(readLine());
}
} no compile error! why not?
throws not here
try/catch must be here
Method propagates an error, i.e. throws an exception
public static String readLine() throws Exception {
… }
Calling code somewhere in the call stack must have a try/catch for that exception
Method handles the error, so must contain a try/catch
public static String readLine() {
try {…} catch (Exception exc1) { handle error}
}
Calling code doesn’t have a try/catch
Should readline propagate the exception or handle it internally?
Is there another alternative that is better?
try {
// stuff
} catch (SomeException e1 ) {
/* do something sensible about the error */
} What to do?
• if caused by user error, give the user a chance to correct it
• take a sensible default action
• print (or display) an error message – where?
• display pop-up dialog, etc.
All exceptions inherit the properties & methods of Throwable
useful methods include:
String getMessage(); // error message
String toString(); // short description
void printStackTrace(); // backtrace
void printStackTrace(PrintStream);
tip: print to standard error stream
System.err.println(“system malfunction”);
try {
// stuff
} catch (SomeException e1 ) {
}
System.err.println( e1.getMessage() );
System.err.println( e1.getClass().getName());
e1.printStackTrace( System.err );
note: use System.err.println() NOT System.out.println()
Consider the BigInteger class in java.math:
public class BigInteger /* arbitrary precision integers */
extends Number
implements Comparable<BigInteger>
/** Returns (this mod m) as a BigInteger
@param m, the modulus, which must be positive
@return this mod m (0, 1, …, m-1)
*/
public BigInteger mod(BigInteger m) {
/* compute and return (this modulo m) */
}
Example: BigInteger
/* application programmer writes the following */
public static void main(…) {
Random RNG = new Random();
BigInteger bi = new BigInteger(50, RNG);
BigInteger ms = new BigInteger(“0”);
System.out.println( bi.mod(ms));
} ERROR – division by zero
/** Returns a BigInteger whose value is (this mod m). @param m the modulus, which must be positive @return this mod m @throws ArithmeticException if m <= 0 */ public BigInteger mod(BigInteger m) throws ArithmeticException { if (m.signum() <= 0) throw new ArithmeticException( “Modulus not positive”); // … } an exception object is created & the call stack is
searched for code to handle the problem
/* application using BigInteger */
public static void main(…) {
Random RNG = new Random();
BigInteger bi = new BigInteger(50, RNG);
BigInteger ms = new BigInteger(“0”);
System.out.println( bi.mod(ms) );
} PROBLEM – where’s the code to handle the error?
Note that the compiler can determine that this is a problem. How? Because the header for BigInteger.mod() specifies that it “throws” an exception (specifically ArithmeticException)
public static void main(…) {
Random RNG = new Random();
BigInteger bi = new BigInteger(50, RNG);
BigInteger ms = new BigInteger(“0”);
try {
System.out.println( bi.mod(ms) );
} catch (ArithmeticException ex) {
System.out.println(ex.getMessage());
}
} Application programmer decides what to do: print an error message? let the user try again? whatever…
for public methods, use Javadoc @throws tag to document the exception that will be thrown
(typically IllegalArgumentException, IndexOutOfBoundsException, or NullPointerException)
nonpublic methods should generally check their parameters using assertions (will cover at a later date)
IllegalArgumentException
parameter value is inappropriate
IllegalStateException
object state is inappropriate
NullPointerException
parameter value is null where prohibited
IndexOutOfBoundsException
index parameter value is out of range
if an error is always the result of a programming error, make it a subclass of RuntimeException (unchecked)
if an error is something the application can recover from: use checked exception class (extends Exception)
the Error class is effectively reserved for the JVM, and is used to indicate resource deficiencies, invariant failures and other conditions that make it impossible to continue execution
String public String(byte[] bytes, int offset, int length)
Constructs a new String by decoding the specified subarray of bytes using the platform's default charset.
Parameters:
bytes - the bytes to be decoded into characters
offset - the index of the first byte to decode
length - the number of bytes to decode
Throws:
IndexOutOfBoundsException - if the offset and the length arguments index characters outside the bounds of the bytes array
try { // do stuff }
catch(IOException ioe) { // handle this case }
catch(UnknownHostException uhe) { // handle this case }
catch(Exception e) { // catch-all }
note that order is important
If any of the code inside the try block throws an exception of the specified types, then
1. the program skips the remainder of the code in the try block
2. the program executes the handler code inside the matching catch clause
If any of the code inside the try block throws a different kind of exception, the method exits immediately (presumably the calling code has a catch clause for that type)
The exception objects, ioe, uhe, contains information about the error that occurred. Can use this when handling the problem.
Item 58: Use checked exceptions for recoverable conditions and run-time exceptions for programming errors
checked – caller can be reasonably be expected to recover from this type of error
run-time – indicates programming errors, such as precondition violations, array out of bounds, etc.
Exception types:
main() Lamp.init() Magic.castSpell()
public class Magic {
public String castSpell( int n) {
char ch = System.in.read();
if (n < 0)
throw new FooException(“you idiot”);
line[-1] = ch;
}
suppose an error occurs
checked
thrown
unchecked (array bounds error)
system error
constructor for Circle throws exception
public Circle(float radius, int x, int y)
throws IllegalArgumentException;
main program contains:
{
Circle c1 = new Circle(9f, 9, 9);
Is there a problem?
}
constructor for Circle throws exception public Circle(float radius, int x, int y) throws
IllegalArgumentException;
main program contains:
try {
float z;
int x, y;
/* code to read values for z, x and y */
Circle c1 = new Circle(z, x, y);
} catch(IllegalArgumentException iae) {
System.err.println(“illegal value”);
}
System.out.println(c1.computeArea());
What’s the problem?
Should this exception even be caught?
import javax.sound.midi.*;
public class TheMusicMan {
public void play() {
Sequencer sequencer = MidiSystem.getSequencer();
System.out.println("We have a sequencer\n");
}
public static void main(String[] args) {
TheMusicMan mm = new TheMusicMan();
mm.play();
}
}
error: unreported exception
MidiUnavailableException; must be
caught or declared to be thrown
public static Sequencer getSequencer()
throws MidiUnavailableException
Returns:
the default sequencer
Throws:
MidiUnavailableException - if the sequencer is not available due to resource restrictions, or there is no Receiver available by any installed MidiDevice, or no sequencer is installed in the system.